解析已在弹簧启动测试定义的端口中使用的端口

我有一个 Spring Boot 应用程序,它启动并执行一个类,该类侦听 Application Ready 事件以调用外部服务来获取一些数据,然后使用该数据将一些规则推送到类路径以执行。对于本地测试,我们模拟了应用程序中的外部服务,该服务在应用程序启动期间工作正常。

问题是在测试应用程序时,通过在以下两个平台上使用弹簧启动测试注释和嵌入式码头容器来运行它:

  • 随机端口
  • 定义的端口

对于 RANDOM PORT,在应用程序启动时,它会从定义端口的属性文件中获取模拟服务的 url,并且不知道嵌入式容器在何处运行,因为它是随机拾取的,因此无法给出响应。

对于 DEFINED PORT,对于第一个测试用例文件,它成功运行,但在拾取下一个文件时,它失败,表示该端口已在使用中。

测试用例在逻辑上分区为多个文件,需要在容器开始加载规则之前调用外部服务。

在使用定义的端口的情况下,如何在测试文件之间共享嵌入式容器,或者在测试用例执行期间启动时重构应用程序代码以获取随机端口。

任何帮助将不胜感激。

应用程序启动代码 :

@Component
public class ApplicationStartup implements ApplicationListener<ApplicationReadyEvent> {

@Autowired
private SomeService someService;

@Override
public void onApplicationEvent(ApplicationReadyEvent arg0) {

    try {
        someService.callExternalServiceAndLoadData();
    }
    catch (Execption e) {}
    }
 }

测试代码注释:测试 1

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@TestPropertySource("classpath:test-application.properties")
public class Test1 {

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    public void tc1() throws IOException {.....}

测试代码注释:Test2

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@TestPropertySource("classpath:test-application.properties")
public class Test2 {

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    public void tc1() throws IOException {.....}

答案 1

如果您坚持在多个测试中使用相同的端口,则可以通过使用以下内容来注释您的 testclass,从而防止 spring 缓存上下文以进行进一步的测试:@DirtiesContext

在您的情况下:

@RunWith(SpringRunner.class)
@DirtiesContext
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@TestPropertySource("classpath:test-application.properties")

以下是安迪·威尔金森(Andy Wilkinson)对这次讨论的回答中的一句话。

这按设计工作。默认情况下,Spring Framework的测试框架将缓存上下文,以便多个测试类可能重用。您有两个具有不同配置的测试(由于@TestPropertySource),因此它们将使用不同的应用程序上下文。第一个测试的上下文将被缓存,并在第二个测试运行时保持打开状态。这两个测试都配置为对 Tomcat 的连接器使用相同的端口。因此,当运行第二个测试时,由于与第一个测试中的连接器发生端口冲突,上下文无法启动。您有几种选择:

  1. 使用RANDOM_PORT
  2. 从 Test2 中删除@TestPropertySource,以便上下文具有相同的配置,并且第一个测试中的上下文可以重用于第二个测试。
  3. 使用@DirtiesContext,以便不缓存上下文

答案 2

我遇到了同样的问题。我知道这个问题有点老了,但这可能会有所帮助:

使用 @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT) 的测试也可以使用 @LocalServerPort 注释将实际端口注入到字段中,如以下示例所示:

资料来源:https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#howto-user-a-random-unassigned-http-port

给出的代码示例是:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
public class MyWebIntegrationTests {

    @Autowired
    ServletWebServerApplicationContext server;

    @LocalServerPort
    int port;

    // ...

}

推荐