问题描述
我有以下情况:
@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
}
测试在所有这些情况下均可成功运行:
- 单独运行测试
- 顺序为:Test1,Test3,Test2
- 顺序为:Test3,Test1,Test2
- 顺序为:Test2,Test3,Test1
- 顺序为:Test2,Test1,Test3
在所有这些情况下,最后运行的测试将失败:
- 顺序为:Test1,Test2,Test3
- 顺序为:Test3,Test2,Test1
我已经研究了这个问题,它与Spring Application Context和wiremock有关。
这是怎么回事?让我们考虑一下测试按以下顺序运行:Test1,Test2,Test3
。
运行Test1
时,将创建一个应用程序上下文(AC1),并在端口1上设置了一个wiremock服务器(WM1),端口1设置为AC1(wiremock.server.port
) WM1连接到测试线程。所有测试通过。
运行Test2
时,将创建另一个应用程序上下文(AC2),并在端口2上设置了一个新的wiremock服务器(WM2),端口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进行存根,但是应用程序其余调用将转到正在侦听端口1的WM1。
我已经尝试清除将@DirtiesContext
添加到Test2的Application Context,因此它将迫使Spring加载第三个AC,但是它不起作用。但是,如果我将@DirtiesContext
添加到Test1或将@DirtiesContext(classMode = BEFORE_CLASS)
添加到Test3,它将起作用。我不需要此解决方案,因为我有其他测试,并且不能保证测试将按哪个顺序运行,因此,如果将其添加到Test3中,则稍后执行顺序将更改,另一个测试将失败。我想要一个真正的解决方案。
有什么想法吗?
解决方法
不确定您是否找到了解决方案,但这是我解决此问题的方法。
当 spring 缓存的测试上下文被重用时,wiremock 端口变回该上下文端口,但似乎错过了配置 WireMock
类默认服务器配置的某些步骤。我们必须在 WireMock.configureFor(port)
或 @Before
方法中使用当前运行的上下文的端口调用 @BeforeEach
。这意味着当我们执行 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);
}