Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@MockBean seems to rerun context creation and fails afterMigrate.sql

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.

like image 523
Sergii Bishyr Avatar asked Dec 22 '22 23:12

Sergii Bishyr


1 Answers

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.

like image 83
Michał Krzywański Avatar answered Jan 07 '23 12:01

Michał Krzywański