I'm doing some integration tests, on a Spring Boot application.
Usually the integration tests that I was used to develop, was regarding the application domain, without any external service involved. Since this time I need to make an integration test on a service which uses both a database and an external service called by an SDK, I've tried doing something like the following:
@RunWith(PowerMockRunner::class)
@SpringBootTest
@PowerMockRunnerDelegate(SpringRunner::class)
@PrepareForTest(McpProductService::class)
class MyServiceIntegration {
@Mock
private ExternalService externalService;
@Autowired
@InjectMocks
private MyServiceImpl myService;
@Test
public void thisTestShouldWork() {
...
}
}
What is confusing me is: how should I declare myService
attribute? Usually when I use Mockito + PowerMock in my Unit Tests, I usually test the implementation, not the whole Service Interface + Spring Injection. But I can't use @Autowired
if I'm using just it's implementation, not the Interface.
Is there any best practice for this issue that I'm facing?
Disclaimer: I'm assuming that what you are after is an end-to-end test of a service interface, backed by multiple classes. I assume (and hope) that you don't have a single class handling both database and webservice integration.
I don't see the need to use PowerMock here, it is usually something one would use for testing legacy code with a lot of static stuff. If you are using Spring boot, your code should be of a quality that makes PowerMock unnecessary.
When writing an end-to-end test, the principles are the same as a per-class unit test, only with a larger scope:
So, here you should find a mechanism to mock the parts of your code that communicates with external sources, like web service clients, database classes (if you don't use an in-memory db for your test (you should)). This will typically be a Spring config that is almost identical to the one used in production, but with said parts mocked out. Then, you just @Inject
the parts you need to communicate with in order to complete the test.
Assuming that you use component scan and annotations for all beans, you could mock the endpoint-classes and use profiles:
This code is based on memory only, might not work on copy-paste, but hopefully you could use the concepts..
@Profile("test")
@Configuration
public class TestConfiguration {
@Bean
@Primary
public SomeWebserviceClient someWebserviceClient() {
return mock(SomeWebserviceClient.class);
}
}
Production code:
@Service
public class SomeClass {
@Inject
private SomeWebserviceClient client;
}
Then in the test:
@RunWith(PowerMockRunner::class)
@SpringBootTest
@ActiveProfiles("test")
public class SomeTest {
@Inject
private SomeClass someClass;
@Inject
private SomeWebserviceClient client; //<< will inject mock
}
Mock will also be injected into SomeClass
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.