How to mock out a deeply nested class in Spring without going insane

Lets say you have a bunch of classes that call each other like this:

Here, Root  calls Middle  which calls End  which calls Database .  If you would like to test from Root , and want to mock out the Database how can you do that in Spring?   Spring doesn’t make this easy. But I have figured out how to do this in a way that I consider satisfactory.

Lets look at at my project layout:




What I like about this solution most is that it keeps the relevant part of the configuration in the test class itself and the rest of the configuration (the @ImportResource ) out of sight. Here’s what I like about this compared to the alternatives I know of:

  1. Springockito has bugs.
  2. Creating a new xml file each time I want a different mock is annoying because I’ll be creating so many.
  3. Using a master test xml file will be painstaking to maintain, especially if I decide I want to use the real database in a specific test.
  4. I don’t think you can initialize a mock in a Spring xml file anyway, at least I haven’t found a way to do it.
  5. Mockito’s @InjectMocks will not Spring-ify the class it works on.
  6. The @Profile annotation mixes too much test and production knowledge together into my configs.  My solution keeps the production configuration ignorant of the test configuration.
  7. If you simply traverse from Root  to End  to manually replace the Database  with a mock, then your tests will become fragile and break when you try to move this call ordering around.  In other words, the test becomes too intimately aware of the way the classes interact with each other and will give you false positive errors.

Some might say that I should swap Database  out with an in memory database.  Some times that make sense, but other times it doesn’t.   Database  doesn’t have to be a “Database”. It can be an API.  It’s not easy to replace an arbitrary API with an in memory API.  That’s where this technique comes in handy.

Others will say, “you shouldn’t write your tests this way”.  Whether that’s wrong or right does not matter.  This article is about showing you how you can do it if you want to, it’s not necessarily a best practice.

If you would like to look at this source code, it is on github here:

Join the email list for bonus content.

Leave a Reply

Your email address will not be published. Required fields are marked *