当前位置: 首页 > 知识库问答 >
问题:

模拟服务/组件的Spring Boot集成测试

尉迟彬
2023-03-14

情况和问题:在Spring Boot中,我如何将一个或多个模拟类/bean注入应用程序以进行集成测试?在StackOverflow上有一些答案,但它们集中在Spring Boot 1.4之前的情况,或者只是不适合我。

背景是,在下面的代码中,设置的实现依赖于第三方服务器和其他外部系统。设置的功能已经在单元测试中测试过了,所以对于完整的集成测试,我想模拟出对这些服务器或系统的依赖,只提供虚拟值。

MockBean将忽略所有现有的bean定义,并提供一个虚拟对象,但该对象在注入该类的其他类中不提供方法行为。在测试之前使用@Before方法设置行为不会影响注入的对象,或者不会注入到其他应用程序服务(如AuthenticationService)中。

我的问题是:如何将bean注入到应用程序上下文中?我的测试:

package ch.swaechter.testapp;

import ch.swaechter.testapp.utils.settings.Settings;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.test.context.junit4.SpringRunner;

@TestConfiguration
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {MyApplication.class})
public class MyApplicationTests {

    @MockBean
    private Settings settings;

    @Before
    public void before() {
        Mockito.when(settings.getApplicationSecret()).thenReturn("Application Secret");
    }

    @Test
    public void contextLoads() {
        String applicationsecret = settings.getApplicationSecret();
        System.out.println("Application secret: " + applicationsecret);
    }
}

下面是一个应该使用模拟类但不接收该模拟类的服务:

package ch.swaechter.testapp;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class AuthenticationServiceImpl implements AuthenticationService {

    private final Settings settings;

    @Autowired
    public AuthenticationServiceImpl(Settings settings) {
        this.settings = settings;
    }

    @Override
    public boolean loginUser(String token) {
        // Use the application secret to check the token signature
        // But here settings.getApplicationSecret() will return null (Instead of Application Secret as specified in the mock)!
        return false;
    }
}

共有2个答案

游鸣
2023-03-14

当您使用@MockBean注释一个字段时,spring将创建一个注释类的mock,并使用它自动连接应用程序上下文的所有bean。

您不得使用创建自嘲

 Settings settings = Mockito.mock(Settings.class);

这将创建第二个模拟,导致所描述的问题。

解决方案:

@MockBean
private Settings settings;

@Before
public void before() {
Mockito.when(settings.getApplicationSecret()).thenReturn("Application Secret");
}

@Test
public void contextLoads() {
    String applicationsecret = settings.getApplicationSecret();
    System.out.println("Application secret: " + applicationsecret);
}
花飞扬
2023-03-14

看起来您正在使用设置对象,然后才指定其模拟行为。你必须跑

Mockito.when(settings.getApplicationSecret()).thenReturn("Application Secret");

在配置设置期间。为了防止这种情况,您可以仅为测试创建特殊配置类。

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {MyApplication.class, MyApplicationTest.TestConfig.class})
public class MyApplicationTest {

    private static final String SECRET = "Application Secret";

    @TestConfiguration
    public static class TestConfig {
        @Bean
        @Primary
        public Settings settingsBean(){
            Settings settings = Mockito.mock(Settings.class);
            Mockito.when(settings.getApplicationSecret()).thenReturn(SECRET);
            Mockito.doReturn(SECRET).when(settings).getApplicationSecret();
            return settings;
        }

    }

.....

}  

我还建议你使用下一个符号来嘲笑:

Mockito.doReturn(SECRET).when(settings).getApplicationSecret();

它不会运行设置::getApplicationSecret

 类似资料:
  • 已删除MyTestConfig.class,但问题仍然相同。即使我使用@SpringBootTest(classes={Application.Class,MyProblematicServiceImpl.Class}),它仍然在自动连线的地方返回模拟对象。MyProblematicServiceImpl是用@Service注释的空类。

  • 我正在用两个应用程序做project:android应用程序(客户端)和rest服务(服务器)。我的android应用程序消耗了我的rest服务。 这两个应用程序都是单独测试的,以确保它们按照预期完成业务。在服务器测试期间,我准备请求并检查服务器响应。在客户机测试期间,我设置了一个简单的http模拟服务器,并针对不同的模拟响应测试客户机的请求。 现在,这个技术很管用。它给了我一种我喜欢的灵活性。我

  • 如何模拟集成测试所需的许多依赖关系? 我使用Mockito进行纯单元测试。在这种情况下,Pure意味着测试一个类,嘲笑它的所有依赖关系。漂亮。 现在是集成测试。假设在这种情况下,集成测试将测试以下内容: 消息被放入队列 我们也可以说,在第2步中发生的处理是严肃的事情。它依赖于大量的数据库交互、多种外部服务、文件系统,以及各种各样的东西。流还会引发很多副作用,所以我不能简单地确保响应是正确的——我需

  • 我已经阅读了数百篇文章和页面,但我无法找到正确的方法来进行集成测试,只模拟一些组件。 这是一个场景:我使用Spring Boot(1.2-snapshot)和各种Spring库创建了一个应用程序,还有Spring data JPA。 我有几个服务,例如Service1和Service2,它们使用Spring数据管理的其他组件和存储库。 如果我想使用嵌入式hsql数据库测试所有服务的完整集成测试,我

  • 我有一个SpringBoot应用程序,它有一个控制器类、一个服务和一个存储库,运行得非常好。我已经为相同的应用程序添加了Junit测试用例,而且效果也非常好。 下面是测试类。 测试用例一直通过,但目前我正在添加另一个API,如下所示,所有测试都失败了。 下面是测试类。 添加部门服务后,测试用例失败,错误如下: 干杯!