Issue
From the official documentation:
When registered by type, any existing single bean of a matching type (including subclasses) in the context will be replaced by the mock
What if the service under test is autowired in the constructor, though? E.g. in Kotlin (I suppose @MockkBean
and @MockBean
work the same regarding DI):
@RunWith(SpringRunner.class)
class ExampleTests @Autowired constructor(val userOfService: UserOfService) {
@MockkBean
private lateinit var service: ExampleService
...
}
I would expect this example to fail because in order to instantiate ExampleTests
Spring has to first obtain a proper instance of UserOfService
. That shouldn't be possible at that time, though, because there's no bean of type ExampleService
in the application context yet.
Contrary to my expectation, this works. How is it possible?
Solution
Because you miss the other part from the documentation :
In either case, if no existing bean is defined a new one will be added.
So @MockBean
will also instantiate a bean automatically if that bean is not found in the spring context.
The sequence of actions are mainly as follows :
Start up the spring context which create all the spring
BeanDefinition
only that are registered in the spring context.Process
@MockBean
which will replace theBeanDefinition
in (1) or create a newBeanDefinition
Actually instantiate all the beans based on these
BeanDefinition
. It will handle which bean to be actually instantiated first and later.Create a test instance (i.e ExampleTests) to execute its test methods. If any beans required to be auto-wired into the test instance are not created , it will fail.
So as long as you define UserOfService
bean , ExampleTests
can be instantiated as you are now using @MockBean
on the ExampleService
which means it must exist no matter you define it or not in the spring context for the test.
Answered By - Ken Chan
Answer Checked By - Marie Seifert (JavaFixing Admin)