【问题标题】:Integration Tests with PowerMock and Spring Boot使用 PowerMock 和 Spring Boot 进行集成测试
【发布时间】:2017-11-16 11:02:20
【问题描述】:

我正在对 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 时,我通常会测试实现,而不是整个 Service Interface + Spring Injection。但是如果我只使用它的实现而不是接口,我就不能使用@Autowired

我面临的这个问题有什么最佳实践吗?

【问题讨论】:

    标签: java testing spring-boot mockito powermock


    【解决方案1】:

    免责声明:我假设您所追求的是由多个类支持的服务接口的端到端测试。我假设(并希望)您没有一个同时处理数据库和 Web 服务集成的类。

    我认为这里没有必要使用 PowerMock,它通常用于测试带有大量静态内容的遗留代码。如果您使用的是 Spring boot,您的代码应该具有不需要 PowerMock 的质量。

    在编写端到端测试时,其原理与 per-class 单元测试相同,只是范围更大:

    • 通过单元测试,您可以创建被测类的实例,并模拟其所有外部依赖项(其他类)
    • 通过端到端测试,您可以创建被测模块的“实例”,并模拟其外部依赖项。

    因此,您应该在这里找到一种机制来模拟与外部源通信的代码部分,例如 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

    【讨论】:

    • 嗯,你说的都是真的。我处于单元测试和 e2e 测试之间。我想要实现的是您在答案的最后部分中解释的内容:运行使用我实现的服务的测试(使用 Spring 上下文)但模拟 @Services 将转到外部资源。 “我假设(并希望)您没有一个同时处理数据库和 Web 服务集成的类”是什么意思?我有一个 @Service 和一些 @Autowired 服务,可以是内部或外部的。
    • 我认为我们在同一页上。执行此操作的实际机制在一定程度上取决于您的项目。我用一个常规的spring项目(不是spring boot)完成了这个,然后我基本上有3个配置文件,一个用于测试(带有模拟),一个用于生产(带有实际端点),一个用于两种情况的通用文件。使用 Spring boot,我猜您可以使用配置文件。我会更新我的答案,但不能保证它会 100% 工作,因为我当时没有任何真实的代码示例。
    • 我会尽量从你的回答中得到我能做到的,然后尝试找出解决方案,谢谢!
    • 更新了我的答案。
    • 让我困惑的是:为什么你说 Powermock 不好?我的意思是,我发现它在单元测试时非常有用。而且我不需要为不同的环境创建不同的配置,而只需要为不同的环境创建不同的属性。我也可以在不使用 Mockito 创建方法和类的情况下运行不同的模拟行为...
    猜你喜欢
    • 2014-08-15
    • 2018-02-01
    • 2020-07-24
    • 2017-03-17
    • 1970-01-01
    • 2020-04-09
    • 1970-01-01
    • 2018-05-04
    • 2020-02-10
    相关资源
    最近更新 更多