【问题标题】:How to not connect to service when testing with Spring?使用 Spring 测试时如何不连接到服务?
【发布时间】:2017-04-10 13:58:14
【问题描述】:

我有一个使用 JHipster 构建的应用程序,其中包含多个测试。 我创建了一个简单的配置类,它实例化一个连接到外部服务的 bean:

@Configuration
public class KurentoConfiguration {

    @Bean(name = "kurentoClient")
    public KurentoClient getKurentoClient(@Autowired ApplicationProperties applicationProperties) {
        return KurentoClient.create(applicationProperties.getKurento().getWsUrl());
    }
}

但正如您所猜想的那样,这段代码在测试期间崩溃,因为外部服务没有启动,但这段代码在应用程序上下文加载期间仍在运行。

所以我需要创建这个 bean 的“无状态”版本以在测试期间使用。

这是一个由于我的配置而失败的测试的简单示例:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Face2FaceApp.class)
public class LogsResourceIntTest {

    private MockMvc restLogsMockMvc;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);

        LogsResource logsResource = new LogsResource();
        this.restLogsMockMvc = MockMvcBuilders
            .standaloneSetup(logsResource)
            .build();
    }

    @Test
    public void getAllLogs()throws Exception {
        restLogsMockMvc.perform(get("/management/logs"))
            .andExpect(status().isOk())
            .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE));
    }
}

在单元测试期间使这个 bean 不高度依赖外部服务的解决方案是什么?

【问题讨论】:

  • 你应该尝试使用一个 MockMvcBuilders 来帮助你像你一样从实际服务构建一个模拟,另外使用一些数据集来为你的测试提供一个内存内置数据库,它是 Spring DBUnit 测试框架的一部分
  • KuretoClient 用在什么地方?它在哪里以及如何注入?不应该将 ApplicationProperties 注入到 KuretoClient 中吗?我没有看到拥有额外类型的好处。
  • @slowy KurentoClient 的实例正在 WebSocket 处理程序上使用。此外,KurentoClient 是一个外部库,因此我无法将其注入内部:/
  • @AnthonyGranger:你可以轻松做到这一点;)。只需定义一个空接口并编写一个学习测试。这样您就可以测试您的预期行为,您可以在系统升级后运行该测试,并且您可以将该库与另一个外部系统交换。而且由于您已经编写了一个接口,因此您可以提供两种不同的 Spring 上下文,一种用于测试,一种用于生产……真正的实现只是委托给 KuretoClient。
  • @slowy 坦克你的回答 :) 但是,我怎么能告诉 Spring 在测试环境中使用我的模拟实现和真正的实现?

标签: java spring testing jhipster kurento


【解决方案1】:

您可以在测试中使用 MockBean 注解来替换现有的 bean:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Face2FaceApp.class)
public class LogsResourceIntTest {

    @MockBean
    private KurentoClient kurentoClient;

    private MockMvc restLogsMockMvc;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);

        LogsResource logsResource = new LogsResource();
        this.restLogsMockMvc = MockMvcBuilders
            .standaloneSetup(logsResource)
            .build();
        given(kurentoClient.someCall()).willReturn("mock");
    }
    ....
}

这是 Spring Boot 文档: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-mocking-beans

【讨论】:

  • 谢谢,但我不直接在我的测试中使用这项服务。它在启动时加载,这就是导致崩溃的原因(外部服务器未运行)
  • 好的,我明白了,在这种情况下,我将使用 powermock 模拟静态方法 KurentoClient.create,例如 '@PrepareForTest(KurentoClient.class)' ... '
  • 或者在@Configuration bean上配置一个测试配置文件
【解决方案2】:

感谢大家的帮助,我设法解决了这个问题:

  • 我创建了一个 KurentoClient 的接口并实现了一个调用 KurentoClient 方法的代理
  • 我的“正常”@Bean kurentoClient 返回实现的代理
  • 我写了一个@TestConfiguration (UnitTestConfiguration) 并添加了一个@Bean,其签名与上面 crated 的签名相同,但这个返回 mockito 的 mock(KurentoClient.class)
  • 我创建了一个类TestBase,每个测试类都扩展了它并且

包含

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyApp.class)
@ContextConfiguration(classes = UnitTestConfiguration.class)
public class TestBase {
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-20
    • 1970-01-01
    • 2021-04-05
    • 1970-01-01
    • 2012-04-11
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    相关资源
    最近更新 更多