I have a spring app and integration tests for this app. I would like to replace a bean with a mock bean.
My real bean looks like this
@Service
public class MyService {
}
and for testing I would like it to be replaced
@Service
public class TestMyService {
}
All I can think of is to use profiles for different services. For example:
@Service
@Profile("!test")
public class MyService implements IMyService {
}
@Service
@Profile("test")
public class TestMyService implements IMyService {
}
And then I autowire the bean like this
@Autowired
private IMyService myService;
Is there a better way?
In an integration test, there is no need to mock away parts of the application. You can replace external systems, but the application works in an integrated way.
This is easily done by using Spring Boot's @MockBean annotation. The Spring Boot test support will then automatically create a Mockito mock of type SendMoneyUseCase and add it to the application context so that our controller can use it.
Spring Boot has @MockBean
and @SpyBean
annotations exactly for this purpose:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-mocking-beans
Declaration is simple:
@MockBean
private MyService myService;
Spring Boot will inject Mockito mock there instead of the actual bean.
My personal preference is to avoid loading the compete context for testing. Therefore I like my test to focus on a subset of beans. It usually means I outline beans which I use in tests:
@RunWith(SpringRunner.class)
@SpringBootTest(
classes = {TestMyService.class, OtherClassNeededForTesting.class}
)
public class DelaysProviderTest {
}
If more configuration is needed I tend to prepare a separate configuration class for tests:
@RunWith(SpringRunner.class)
@SpringBootTest(
classes = MyTest.Cfg.class
)
public class MyTest {
@Import({
// .. some classes to import including TestMyService.class
})
@Configuration
public static class Cfg {
}
}
When even more configuration is needed (or mocking), I use the test configuration for providing appropriate mocks
@RunWith(SpringRunner.class)
@SpringBootTest(
classes = MyTest.Cfg.class
)
public class MyTest {
@Import({
// .. some classes to import
})
@Configuration
public static class Cfg {
@Bean
public IMyService service() {
IMyService mock = Mockito.mock(IMyService.class);
when(mock.someMethod()).thenReturn("some data");
return mock;
}
}
}
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