Reputation: 730
To avoid the Spring context reloading again and again, I have moved @MockBean
annotated injection to a parent class, something like this.
@SpringBootTest
.......
public abstract BaseTest {
@MockBean
protected OneService oneService;
This serves the test classes which need a mock for OneService
. However, for the test that I would like also extended from BaseTest
, but inject the real OneService
via @Autowired
will not work, as it will inherit the mock injection from the BaseTest
.
public AnotherTest extends BaseTest {
@Autowired
protected OneService oneService;
Even I used @Autowired
annotation, the oneService
field will be the mock instance inherited from BaseTest
.
Is there a way I can force inject to use autowired?
Upvotes: 10
Views: 4010
Reputation: 31197
In Java there is technically no way to override a field. When you declare a field with the same name in a subclass, that field shadows the field with the same name in the superclass. So that is one hurdle.
The second hurdle stems from the fact that there is no way in Spring Boot's testing support to turn off mocking of a bean in a subclass if the superclass configures the mocking via @MockBean
.
Thus, the solution is to invert what you are trying to do by having the real bean injected via @Autowired
in the superclass and then turn on mocking for the specific bean type in the subclass.
@Autowired
field in the superclass but do not redeclare the field in the subclass.@MockBean
at the class level in the subclass, specifying which classes (i.e., bean types) to be mocked.That last step results in the inherited field being injected with a mock in the subclass.
The following two classes demonstrate this technique in practice.
@SpringBootTest(classes = BaseTests.Config.class)
class BaseTests {
@Autowired
protected Service service;
@Test
void service() {
assertThat(service.getMessage()).isEqualTo("real");
}
@Configuration
static class Config {
@Bean
Service service() {
return new Service();
}
}
static class Service {
String getMessage() {
return "real";
}
}
}
@MockBean(classes = BaseTests.Service.class)
class MockBeanTests extends BaseTests {
@BeforeEach
void setUpMock() {
when(service.getMessage()).thenReturn("mock");
}
@Test
@Override
void service() {
assertThat(service.getMessage()).isEqualTo("mock");
}
}
Upvotes: 8