I have two integration test classes. One of these classes depends on the bean that is talking to external service, so I need to mock this bean, and @MockBean
seems perfect for this. For injecting some seeds into DB I'm using flyway
's afterMigrate.sql
. So here is hot it looks like:
@RunWith(SpringRunner.class)
@ActiveProfiles("test")
@SpringBootTest
@Transactional
@Rollback
class FooTest {
@Autowired
private MyService myService;
}
@RunWith(SpringRunner.class)
@ActiveProfiles("test")
@SpringBootTest
@Transactional
@Rollback
class BarTest {
@MockBean
private ExternalService;
@Autowired
private MyService myService;
}
And afterMigrate.sql
:
INSERT INTO my_table (id, name) VALUES (1, 'John Doe')
The problem appeared when I annotate the ExternatService
as @MockBean
as now the afretMigrate.sql
runs twice and I'm getting the error:
java.lang.IllegalStateException: Failed to load ApplicationContext
....
Message : ERROR: duplicate key value violates unique constraint "my_table_pkey"
When I'm changing the @MockBean
to @Autowired
the error is gone and context is created without any problems. Also, tests run without problems if I run BarTest
separately.
This is not the expected behavior for @MockBean
as the documentation says:
Any existing single bean of the same type defined in the context will be replaced by the mock. If no existing bean is defined a new one will be added. Dependencies that are known to the application context but are not beans (such as those registered directly) will not be found and a mocked bean will be added to the context alongside the existing dependency.
It does not say that the context will be recreated.
Because when you use @MockBean
annotation your context will be loaded for each test. Please refer to this github issue. The citation from this page :
The Spring test framework will cache an ApplicationContext whenever possible between test runs. In order to be cached, the context must have an exactly equivalent configuration. Whenever you use @MockBean, you are by definition changing the context configuration.
So when you use your mock bean in different tests - the context will be recreated each time for your test class. So if you for example have some beans that load data to DB on context creation - for example beans for flyway - they will be created each time context is recreated.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With