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

Spring Boot集成测试——在应用程序上下文启动之前模拟@Service?

辛才俊
2023-03-14

我必须为microservice X创建一个集成测试,它可以从外部sftp服务器下载、处理和导入csv文件。整个过程由一个Spring Boot调度程序任务启动,该任务启动一个spring批处理作业来处理和导入数据。导入过程由spring batch writer完成,它是一个restTemplate存储库(因此它调用对另一个微服务的post请求)。

我已经设法模拟了sftp服务器,在其上放置了一个测试文件,当前的集成测试正在下载该文件。(html" target="_blank">https://github.com/stefanbirkner/fake-sftp-server-rule/)

我的问题是,任务将在应用程序上下文启动时立即安排,因此没有像api调用那样的触发器。为了让整个集成测试正常工作,我必须模拟通过restTemplate调用外部微服务Y的部分。该存储库在spring batch writer中被调用,该存储库由一个名为@Service的repositoryFactory创建。repositoryFactory被注入spring批处理配置类中。

我已经尝试在测试类中以及在一个单独的测试配置中使用@MockBean注释,在这个配置中,我嘲笑工厂的create()函数来提供一个存储库模拟。但是在某个时候它不起作用,它仍然提供原始对象,这导致中断导入作业。

我也尝试使用WireMock库,但在这种情况下,它不捕获任何api调用,并在某些时候导致中断sftp套接字。(?)

我希望有人能帮我。

当前的测试:

@NoArgsConstructor
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(classes = {JsonHalConfig.class})
@TestPropertySource(locations = "classpath:application-test.properties")
@TestMethodOrder(MethodOrderer.MethodName.class)
public class ImportIT {

    @ClassRule
    public static final FakeSftpServerRule sftpServer = new FakeSftpServerRule();
    private static final String PASSWORD = "password";
    private static final String USER = "username";
    private static final int PORT = 14022;

    @BeforeClass
    public static void beforeClass() throws IOException {
        URL resource = getTestResource();
        if (resource != null) {
            sftpServer.setPort(PORT).addUser(USER, PASSWORD);
            sftpServer.createDirectories("/home/username/it-space/IMPORT", "/home/username/it-space/EXPORT");
            sftpServer.putFile("/home/username/it-space/IMPORT/INBOX/testFile.csv",
                    resource.openStream());
        } else {
            throw new IOException("Failed to get test resources");
        }
    }

    private static URL getTestResource() {
        return ImportIT.class.getClassLoader().getResource("testFile.csv");
    }

    @Test
    public void test_A_() throws IOException, RepositoryException {
        assertTrue(true);
    }
}

我尝试了以下配置类

(包含在@ContextConfigance中)

@Configuration/@TestConfiguration
public class RepositoryTestConfig {
    @Bean
    @Primary
    public IRepositoryFactory repositoryFactory() {
        IRepositoryFactory repositoryFactory = mock(IRepositoryFactory.class);
        IRepository repository = mock(IRepository.class);
        when(repositoryFactory.create(anyString())).thenReturn(repository);
        return repositoryFactory;
    }
}

(作为测试类中的静态类)

    @TestConfiguration/@Configuration
    public static class RepositoryTestConfig {
        @MockBean
        private IRepositoryFactory repositoryFactory;

        @PostConstruct
        public void initMock(){
            IRepository repository = mock(IRepository.class);
            Mockito.when(repositoryFactory.create(anyString())).thenReturn(
                    repository
            );
        }
    }

更新27.08.2021我有一个RestConfig@Component,其中创建了一个新的RestTemplateBuilder。我试图@MockBean这个组件来传递一个restemplatebuilder Mock,并注入一个MockRestServiceServer对象来捕获传出的api调用。但不幸的是,它并不像aspected那样有效。我错过什么了吗?我还试图创建一个“TestRestController”来触发任务的调度,但它从未提供模拟。。。

共有1个答案

乐正镜
2023-03-14

我通常直接在我的测试类中使用@MockBean,并直接在那里注入专用(但被模拟的)存储库,而不是在测试配置中创建它。我还通过@ContextConfigance添加测试配置类,以便将其加载到当前测试上下文中。

在我的测试中,我只是以标准方式使用mockito,并按照专用测试方法的要求准备模拟部件。

下面是一个示例片段:

// ... do some imports ...
@RunWith(SpringRunner.class)
@ContextConfiguration(classes= {XYZSomeWantedClazz.class, DemoXYZMockTest.SimpleTestConfiguration.class})
@ActiveProfiles({Profiles.TEST})
public class DemoXYZMockTest {
   //...
   @MockBean
   private DemoRepository mockedDemoRepository;
   // ...
   @Test
   public void testMethodName() throws Exception{
       /* prepare */
       List<WantedEntityClazz> list = new ArrayList<>();
       // add your wanted data to your list

       // apply to mockito:
       when(mockedDemoRepository.findAll()).thenReturn(list);

       /* execute */
       // ... execute the part you want to test...
 
       /* test */
       // ... test the results after execution ...

   }


   @TestConfiguration
   @Profile(Profiles.TEST)
   @EnableAutoConfiguration
   public static class SimpleTestConfiguration{
      // .. do stuff if necessary or just keep it empty
   }

}

有关完整的(旧的Junit4)工作测试示例,请参阅:https://github.com/Daimler/sechub/blob/3f176a8f4c00b7e8577c9e3bea847ecfc91974c3/sechub-administration/src/test/java/com/daimler/sechub/domain/administration/signup/SignupAdministrationRestControllerMockTest.java

 类似资料:
  • 我需要在REST级别编写一个e2e测试,发送真正的请求。所以我想用应用上下文,而不是嘲讽豆。 有一个自动连接的,以及此<code>MyService。类依赖于两个存储库类。因此,我尝试模拟,并以以下方式将它们注入真正的: 但我得到了以下错误: 我还尝试使用< code > @ context configuration(classes = { my config . class })没有成功: 我

  • 使用spring-boot时,一切工作都很好。尽管如此,在spring-boot中已删除了注释和。我试图将代码重构为新版本,但我做不到。对于以下测试,我的应用程序在测试之前没有启动,http://localhost:8080返回404: 如何重构测试以使其在Spring-Boot1.5中工作?

  • 正如标题所示,我正在寻找任何可以帮助我在Springs应用程序上下文(准确地说是持久性上下文)加载之前运行Flyway迁移的方法。原因是我在应用程序启动时运行的查询很少。这导致我的测试失败,因为正在对尚不存在的数据库表执行查询。我使用H2作为我的测试数据库。现在我只使用flyway核心依赖: 我有一个单一的Flyway配置类,如下所示: 并且属性在 我想实现的是:1.飞行路线做迁移2。Spring

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

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

  • 我被要求在一个非常大的SpringBoot项目中为一个服务创建一个集成测试,该项目产生了几十个已实现的服务。当应用程序执行时,所有这些服务都被部署了——我希望避免部署与我正在为其创建测试的服务无关的所有服务。不幸的是,我(还)没有像我希望的那样有很多Spring启动测试的经验,因此我想知道解决这个问题的最佳方法是什么。 我曾考虑在测试类中使用注释对所有不相关的服务进行注释,并使用对所有相关服务进行