Spring Data Mock DAO
Warning, the following code example is suitable for a narrow range of use cases… but it’s strangely useful.
When writing tests against Spring services or controllers, we may wish to mock the DAO layer completely. This can be achieved:
@MockBean private MyDao myDao;
And the mock dao is then wired into our services etc.
However, there are situations where we’re doing something complex in a higher order test, and we want this DAO to function just enough. This is where the following function may help:
/** * Turn any integer keyed mock dao into a sort of working one for save and findById * * @param mockDao the dao to mock * @param <T> the type of element */ static <T> void givenFakeSaveAndLoad(CrudRepository<T, Integer> mockDao, Function<T, Integer> getId, BiConsumer<T, Integer> setId) { Map<Integer, T> fakeDb = new HashMap<>(); AtomicInteger idGenerator = new AtomicInteger(123); given(mockDao.save(any())) .willAnswer(answer((T toSave) -> { if (getId.apply(toSave) == null) { setId.accept(toSave, idGenerator.getAndIncrement()); } fakeDb.put(getId.apply(toSave), toSave); return toSave; })); willAnswer(answer((Integer id) -> Optional.ofNullable(fakeDb.get(id)))) .given(mockDao) .findById(argThat(id -> id >= 123)); }
What this is doing is simulating a really simple database by using a Map
. It can operate on any CrudRepository
where the key field is an Integer
. Technically you could make it operate on other key types if you wanted to. I’m using AtomicInteger
as the key generator here, so Integer
is all I want.
What this code does is puts a POJO in a Map
on save and retrieves it from the Map
on findById
. There are many ways this is not enough of a mock of a database… but let’s just look at an example of using it:
givenFakeSaveAndLoad(learnerDriverDao, LearnerDriver::getId, LearnerDriver::setId);
We call it with the DAO we wish to mock and the functions on the POJO that access its ID field. Then it adds this moderately handy map-based DAO.
Why It’s Rubbish
Loads of reasons why this is not a good idea:
- The POJO stored in the
Map
is mutable, so any code that modifies it will affect the database’s copy. - DAOs have many more methods than
save
andfindById
and this doesn’t cover them - Tests that rely on stateful mock objects soon get out of hand
Conversely, this is a simple pattern that’s really helped make a few tests easy!
Published on Java Code Geeks with permission by Ashley Frieze, partner at our JCG program. See the original article here: Spring Data Mock DAO Opinions expressed by Java Code Geeks contributors are their own. |