Spring 使用 WireMock 的 JUnit 测试中的多个应用程序上下文

Multiple Application Contexts in Spring JUnit test with WireMock

我有以下场景:

@Transactional
@SpringBootTest
@ActiveProfiles("test")
@AutoConfigureMockMvc
@AutoConfigureWireMock(port = 0)
public abstract class IntegrationTest {
}

public class Test1 extends IntegrationTest {
  // Tests that use WireMock
}

@ActiveProfiles("specific-case-test") // This causes another Application Context to be created.
public class Test2 extends IntegrationTest {
  // Tests that use WireMock
}

public class Test3 extends IntegrationTest {
  // Tests that use WireMock
}

测试 运行 在所有这些场景中都成功:

对 运行 的最后一次测试在所有这些情况下都失败了:

我已经调查了这个问题,它与 Spring Application Context 和 WireMock 有关。

这是怎么回事?让我们考虑测试 运行 的顺序:Test1, Test2, Test3.

Test1 运行s时,一个Application Context(AC1)被创建,一个WireMock服务器(WM1)被设置,比方说,在端口1上。端口1设置为AC1 (wiremock.server.port) 并且 WM1 附加到测试线程。所有测试通过。

Test2 运行s时,创建了另一个应用程序上下文(AC2)并设置了一个新的WireMock服务器(WM2),比方说,在端口2上。端口2设置为AC2 (wiremock.server.port) 和 WM2 附加到测试线程,替换 WM1。所有测试通过。

Test3 运行 时,它会重新使用 AC1,这会导致测试失败并显示消息:404 Not Found: [No response could be served as there are no stub mappings in this WireMock instance.]。 应用程序状态是 wiremock.server.port 为 1(来自 AC1)并且 WM2 附加到测试线程。因此,对 WM2 进行存根,但应用程序 rest 调用将转到 WM1,它正在侦听端口 1。

我已经尝试清理应用程序上下文,将 @DirtiesContext 添加到 Test2,因此它会强制 Spring 加载第三个 AC,但它不起作用。但是,如果我将 @DirtiesContext 添加到 Test1 或将 @DirtiesContext(classMode = BEFORE_CLASS) 添加到 Test3 它会起作用。我不想要这个解决方案,因为我有其他测试并且无法保证测试的顺序 运行,所以如果我将它添加到 Test3,那么稍后执行顺序将改变并且另一个测试将失败。我想要一个真正的解决方案。

有什么想法吗?

不确定您是否找到了解决方案,但我是这样解决的。

当 spring 缓存的测试上下文被重用时,wiremock 端口变回那个上下文端口,但似乎错过了配置 WireMock 类 默认服务器配置的一些步骤。我们必须使用当前 运行 上下文的端口在 @Before@BeforeEach 方法中调用 WireMock.configureFor(port)。这意味着当我们执行 stubFor 方法调用时,正确的 WireMock 端口被命中并且服务器正确配置了我们的存根,确保您在任何重置之前也执行此配置。

@Autowired
private Environment environment;

private String getWiremockServerPort() {
    // Get the auto configured port property from the current Spring contexts environment
    return environment.getProperty("wiremock.server.port");
}

@BeforeEach
private void configureWireMockPortToMatchEnvironmentContext() {
    int contextEnvironmentPort = Integer.parseInt(getWiremockServerPort());
    configureFor(contextEnvironmentPort);
}