我正在Spring Boot应用程序上进行一些集成测试。
通常,我用来开发的集成测试是关于应用程序域的,不涉及任何外部服务。由于这次我需要对一个同时使用数据库和SDK调用的外部服务的服务进行集成测试,我尝试了如下操作:
@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() {
...
}
}
让我困惑的是:我应该如何声明myService
属性?通常,当我在单元测试中使用Mockito+PowerMock时,我通常会测试实现,而不是整个服务接口+Spring注入。但是,如果我只使用它的实现,而不是接口,那么我就不能使用@Autowired
。
对于我面临的这个问题,有什么最佳实践吗?
免责声明:我假设您所追求的是由多个类支持的服务接口的端到端测试。我假设(并希望)您没有一个类同时处理数据库和Web服务集成。
我认为这里没有必要使用PowerMock,它通常用于测试带有大量静态内容的遗留代码。如果您使用的是Spring引导,那么您的代码应该具有使PowerMock变得不必要的质量。
在编写端到端测试时,原理与每类单元测试相同,只是范围更大:
- 使用单元测试,您可以创建被测试类的实例,并模拟其所有外部依赖项(其他类)
- 使用端到端测试,您可以创建被测模块的"实例",并模拟其外部依赖关系
因此,在这里,您应该找到一种机制来模拟代码中与外部源通信的部分,如web服务客户端、数据库类(如果您的测试不使用内存中的数据库(您应该))。这通常是一个Spring配置,与生产中使用的配置几乎相同,但所述部件被模拟出来。然后,您只需@Inject
您需要与之通信的部件即可完成测试。
假设您对所有bean使用组件扫描和注释,则可以模拟端点类并使用概要文件:
这段代码仅基于内存,可能不适用于复制粘贴,但希望您可以使用这些概念。。
@Profile("test")
@Configuration
public class TestConfiguration {
@Bean
@Primary
public SomeWebserviceClient someWebserviceClient() {
return mock(SomeWebserviceClient.class);
}
}
生产代码:
@Service
public class SomeClass {
@Inject
private SomeWebserviceClient client;
}
然后在测试中:
@RunWith(PowerMockRunner::class)
@SpringBootTest
@ActiveProfiles("test")
public class SomeTest {
@Inject
private SomeClass someClass;
@Inject
private SomeWebserviceClient client; //<< will inject mock
}
Mock也将被注入SomeClass