我有以下场景:
@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
}
测试在所有这些场景中都能成功运行:
- 单独运行测试
- 按顺序:测试1、测试3、测试2
- 按顺序:测试3、测试1、测试2
- 按顺序:测试2、测试3、测试1
- 按顺序:测试2、测试1、测试3
在所有这些情况下运行的最后一个测试失败:
- 按顺序:Test1、Test2、Test3
- 按顺序:测试3、测试2、测试1
我已经调查了这个问题,它与Spring应用程序上下文和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进行存根处理,但应用程序rest调用将转到正在端口1上侦听的WM1。
我已经尝试过清理向Test2添加@DirtiesContext
的应用程序上下文,所以它会强制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);
}
如果您以这种方式创建Wiremock存根:
stubFor(post(urlEqualTo(CALLBACK))
.willReturn(aResponse().withStatus(202))
);
在使用静态方法"的情况下;stubFor&";从com.github.tomakehurst.wiremock.client.wiremock,您可以尝试在测试类中添加一个自动连线的WiremockServer对象:
@Autowired
protected WireMockServer wireMockServer;
然后将存根创建替换为:
wireMockServer.stubFor(post(urlEqualTo(CALLBACK))
.willReturn(aResponse().withStatus(202))
);
其中使用了com.github.tomakehurst.wiremock.WireMockServer.中的非静态方法
就我而言,这解决了问题。