In the last couple of posts we’ve discussed how we can use mocks in Spring integration testing. We’ve covered using a bean “prototype” and resetting mocks.
There is one more option.
The MockBean
By now you’re probably thinking: Those Spring guys must understand the need for proper mocking in integration tests. Didn’t they think about this stuff?
Well, of course they did. It’s called a MockBean.
A MockBean bean is injected by Spring, for testing purposes, for every integration test. And we get a nice shiny unscratched instance for each test. We don’t even need to handle auto-wiring, create a configuration and reset anything. Spring does all this magic for us.
This time, our integration test class looks like this:
@RunWith(SpringRunner.class)
@SpringBootTest
public class MockPublisherMockBeanTests {
@MockBean Publisher mockPublisher;
@Test
public void firstTest() {
mockPublisher.publish();
Mockito.verify(mockPublisher).publish();
}
@Test
public void secondTest() {
verify(mockPublisher, never()).publish();
}
}
Code language: CSS (css)
Notice, we are not importing any configuration (or creating a bean). Instead of @Autowired instance we’ve got a @MockBean. That’s all it takes. Spring does the rest. Note that since there’s no configuration, all the set up should be done in the test class itself.
Everything you wanted to know about MockBeans but were afraid to ask
A @MockBean overrides by default a pre-configured bean. That means that if we import a Configuration with the same type of bean, the @MockBean is injected as a mock, overriding the factory method in Configuration class.
Also, remember that a @MockBean is a mock like any other Mockito mock, and therefore has defaults. If you want to change those (for example, change to a preferred deep-stubbing option, you can use it like this:
@MockBean(answer=Answers.RETURNS_DEEP_STUBS)
Publisher mockPublisher;
Code language: CSS (css)
Finally, we know that a @MockBean resets after every test by default. If you want to change this option, you can use the reset before every test, or not at all.
@MockBean(reset=MockReset.NONE)
Publisher mockPublisher;
Code language: CSS (css)
Although that last one kinda misses the point.
On one hand, using a @MockBean gives good isolation from other test classes, since, as we’ve seen last time, it may be erased by an erroneous reset.
On the other hand, that may also be a limitation – if there are multiple setups we need on it, not just for our integration test class. Imagine we need to create mock object tree for multiple test classes to consume as a starting point, and each one customizes it for its purposes. In that case, the way to go is probably a prototype, and being very careful with resets.
That’s all about mocking for now. Next time: Data stuff.
Check out the following workshops where I talk about testing in Spring:
0 Comments