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:
1 2 | @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:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | /** * 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:
1 2 3 | 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. |