Citrus Framework 异步 HTTP 测试场景
Citrus Framework async HTTP test scenario
我有异步测试场景。我调用我的 SUT(被测系统),它 returns 确认响应。接下来异步返回正确的响应。我配置了指定接收回调响应的模拟服务器,如下所示:
<citrus-http:server id="receiveCallbackMockService"
port="${server.port}"
auto-start="true"
timeout="10000"
endpoint-adapter="dispatchingEndpointAdapter" />
<citrus:dispatching-endpoint-adapter id="dispatchingEndpointAdapter"
mapping-key-extractor="mappingKeyExtractor"
mapping-strategy="mappingStrategy"/>
<bean id="mappingKeyExtractor" class="com.consol.citrus.endpoint.adapter.mapping.HeaderMappingKeyExtractor">
<property name="headerName" value="#{T(com.consol.citrus.http.message.HttpMessageHeaders).HTTP_REQUEST_URI}"/>
</bean>
<bean id="mappingStrategy"
class="com.consol.citrus.endpoint.adapter.mapping.SimpleMappingStrategy">
<property name="adapterMappings">
<map>
<entry key="/callback" value-ref="responseAdapter"/>
</map>
</property>
</bean>
<citrus:static-response-adapter id="responseAdapter">
</citrus:static-response-adapter>
然后我使用 Java DSL 代码,它应该在回调时接收预期的有效负载
receive(receiveCallbackMockService)
.payload(new ClassPathResource("/async/callbackExpectedRequest01.xml"));
但是我在执行测试时遇到这样的异常:
14:25:43,516 ERROR citrus.Citrus| TEST FAILED HELLO_ASYNC_01: output 039 <com.mycompany.myproject> Nested exception is:
com.consol.citrus.exceptions.CitrusRuntimeException: Unable to create endpoint for static endpoint adapter type 'class com.consol.citrus.endpoint.adapter.RequestDispatchingEndpoint
Adapter'
at com.consol.citrus.endpoint.adapter.StaticEndpointAdapter.getEndpoint(StaticEndpointAdapter.java:35)
at com.consol.citrus.server.AbstractServer.createConsumer(AbstractServer.java:200)
at com.consol.citrus.actions.ReceiveMessageAction.receive(ReceiveMessageAction.java:146)
at com.consol.citrus.actions.ReceiveMessageAction.doExecute(ReceiveMessageAction.java:125)
at com.consol.citrus.actions.AbstractTestAction.execute(AbstractTestAction.java:42)
at com.consol.citrus.dsl.actions.DelegatingTestAction.doExecute(DelegatingTestAction.java:54)
at com.consol.citrus.actions.AbstractTestAction.execute(AbstractTestAction.java:42)
at com.consol.citrus.TestCase.executeAction(TestCase.java:214)
at com.consol.citrus.TestCase.doExecute(TestCase.java:142)
at com.consol.citrus.actions.AbstractTestAction.execute(AbstractTestAction.java:42)
at com.consol.citrus.Citrus.run(Citrus.java:254)
at com.consol.citrus.dsl.testng.TestNGCitrusTest.invokeTestMethod(TestNGCitrusTest.java:124)
at com.consol.citrus.dsl.testng.TestNGCitrusTestDesigner.invokeTestMethod(TestNGCitrusTestDesigner.java:73)
at com.consol.citrus.dsl.testng.TestNGCitrusTest.run(TestNGCitrusTest.java:100)
at com.consol.citrus.dsl.testng.TestNGCitrusTest.run(TestNGCitrusTest.java:58)
at org.testng.internal.MethodInvocationHelper.invokeHookable(MethodInvocationHelper.java:209)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:639)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:820)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1128)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:129)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:112)
at org.testng.TestRunner.privateRun(TestRunner.java:782)
at org.testng.TestRunner.run(TestRunner.java:632)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:366)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:361)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:319)
at org.testng.SuiteRunner.run(SuiteRunner.java:268)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1244)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1169)
at org.testng.TestNG.run(TestNG.java:1064)
at org.apache.maven.surefire.testng.TestNGExecutor.run(TestNGExecutor.java:132)
at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.executeMulti(TestNGDirectoryTestSuite.java:224)
at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.execute(TestNGDirectoryTestSuite.java:113)
at org.apache.maven.surefire.testng.TestNGProvider.invoke(TestNGProvider.java:146)
at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:286)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:240)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:121)
我应该如何配置 Citrus HTTP Mock Server 以在异步测试场景中接收回调请求(并使用预期的请求有效负载对其进行验证)?
您同时在 Citrus 服务器组件上使用静态响应适配器和 receive() 操作。这是行不通的。静态响应适配器将始终跳入,并且您测试中的接收操作永远不会收到任何请求。
如果您想在测试用例中接收来自该服务器组件的请求,请删除调度响应适配器和静态响应适配器。
刚抽出时间来分享我的解决方案。首先 - 有一个 post (http://citrus.895196.n3.nabble.com/Citrus-to-act-as-a-mock-server-td4023066.html) 告诉我们,"What you need is a standalone simulator that waits for incoming requests and sends pre-defined response messages. This is not the primary focus of Citrus as a test framework."。但我找到了解决方法:
1) 使用全局变量作为标志告诉我们,异步请求是否从 SUT 到达:
Spring 上下文:
<bean id="globalVariables" class="com.consol.citrus.variables.GlobalVariables"></bean>
Java代码:
@Autowired
private GlobalVariables globalVariables
并在开始等待 SUT 异步回调请求之前设置变量(标志)
globalVariables.getVariables().put("SUTcallbackStatus", "waiting");
2) 扩展 IteratingConditionExpression
- 重写 evaluate
方法,如下所示:
@Override
public boolean evaluate(int index, TestContext context) {
if(index > threshold){
testToFail.fail("The async message didn't arrived to the mock server.");
return false;
}
if(globalVariables.getVariables().get("SUTcallbackStatus").equals("received")){
return false;
}
return true;
}
上面代码中的 testToFail
和 threshold
变量应该从测试中设置 class:
myIteratingConditionExpression.setThreshold(50);
myIteratingConditionExpression.setTestToFail(this);
它允许您控制测试应等待响应的时间(threshold
*0.5
秒)并允许您指向测试,如果未收到回调则应失败假定期间的响应。
3) 扩展 StaticResponseEndpointAdapter
- 重写下面的方法
@Override
public Message handleMessageInternal(Message message) {
globalVariables.getVariables().put("SUTcallbackStatus", "received");
return super.handleMessageInternal(message);
}
并将此适配器用作您的模拟服务适配器:
<citrus-http:server id="asyncResponseMockService"
port="${server.callback.port}"
auto-start="true"
timeout="10000"
endpoint-adapter="myResponseAdapter" />
4) 然后,在您的测试中 class - 开始等待异步回调请求 - 只需使用带有自定义迭代条件表达式的 iterate
操作:
iterate(sleep(0.5)).condition(myIteratingConditionExpression);
这对我有用:)
我有异步测试场景。我调用我的 SUT(被测系统),它 returns 确认响应。接下来异步返回正确的响应。我配置了指定接收回调响应的模拟服务器,如下所示:
<citrus-http:server id="receiveCallbackMockService"
port="${server.port}"
auto-start="true"
timeout="10000"
endpoint-adapter="dispatchingEndpointAdapter" />
<citrus:dispatching-endpoint-adapter id="dispatchingEndpointAdapter"
mapping-key-extractor="mappingKeyExtractor"
mapping-strategy="mappingStrategy"/>
<bean id="mappingKeyExtractor" class="com.consol.citrus.endpoint.adapter.mapping.HeaderMappingKeyExtractor">
<property name="headerName" value="#{T(com.consol.citrus.http.message.HttpMessageHeaders).HTTP_REQUEST_URI}"/>
</bean>
<bean id="mappingStrategy"
class="com.consol.citrus.endpoint.adapter.mapping.SimpleMappingStrategy">
<property name="adapterMappings">
<map>
<entry key="/callback" value-ref="responseAdapter"/>
</map>
</property>
</bean>
<citrus:static-response-adapter id="responseAdapter">
</citrus:static-response-adapter>
然后我使用 Java DSL 代码,它应该在回调时接收预期的有效负载
receive(receiveCallbackMockService)
.payload(new ClassPathResource("/async/callbackExpectedRequest01.xml"));
但是我在执行测试时遇到这样的异常:
14:25:43,516 ERROR citrus.Citrus| TEST FAILED HELLO_ASYNC_01: output 039 <com.mycompany.myproject> Nested exception is:
com.consol.citrus.exceptions.CitrusRuntimeException: Unable to create endpoint for static endpoint adapter type 'class com.consol.citrus.endpoint.adapter.RequestDispatchingEndpoint
Adapter'
at com.consol.citrus.endpoint.adapter.StaticEndpointAdapter.getEndpoint(StaticEndpointAdapter.java:35)
at com.consol.citrus.server.AbstractServer.createConsumer(AbstractServer.java:200)
at com.consol.citrus.actions.ReceiveMessageAction.receive(ReceiveMessageAction.java:146)
at com.consol.citrus.actions.ReceiveMessageAction.doExecute(ReceiveMessageAction.java:125)
at com.consol.citrus.actions.AbstractTestAction.execute(AbstractTestAction.java:42)
at com.consol.citrus.dsl.actions.DelegatingTestAction.doExecute(DelegatingTestAction.java:54)
at com.consol.citrus.actions.AbstractTestAction.execute(AbstractTestAction.java:42)
at com.consol.citrus.TestCase.executeAction(TestCase.java:214)
at com.consol.citrus.TestCase.doExecute(TestCase.java:142)
at com.consol.citrus.actions.AbstractTestAction.execute(AbstractTestAction.java:42)
at com.consol.citrus.Citrus.run(Citrus.java:254)
at com.consol.citrus.dsl.testng.TestNGCitrusTest.invokeTestMethod(TestNGCitrusTest.java:124)
at com.consol.citrus.dsl.testng.TestNGCitrusTestDesigner.invokeTestMethod(TestNGCitrusTestDesigner.java:73)
at com.consol.citrus.dsl.testng.TestNGCitrusTest.run(TestNGCitrusTest.java:100)
at com.consol.citrus.dsl.testng.TestNGCitrusTest.run(TestNGCitrusTest.java:58)
at org.testng.internal.MethodInvocationHelper.invokeHookable(MethodInvocationHelper.java:209)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:639)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:820)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1128)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:129)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:112)
at org.testng.TestRunner.privateRun(TestRunner.java:782)
at org.testng.TestRunner.run(TestRunner.java:632)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:366)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:361)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:319)
at org.testng.SuiteRunner.run(SuiteRunner.java:268)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1244)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1169)
at org.testng.TestNG.run(TestNG.java:1064)
at org.apache.maven.surefire.testng.TestNGExecutor.run(TestNGExecutor.java:132)
at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.executeMulti(TestNGDirectoryTestSuite.java:224)
at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.execute(TestNGDirectoryTestSuite.java:113)
at org.apache.maven.surefire.testng.TestNGProvider.invoke(TestNGProvider.java:146)
at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:286)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:240)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:121)
我应该如何配置 Citrus HTTP Mock Server 以在异步测试场景中接收回调请求(并使用预期的请求有效负载对其进行验证)?
您同时在 Citrus 服务器组件上使用静态响应适配器和 receive() 操作。这是行不通的。静态响应适配器将始终跳入,并且您测试中的接收操作永远不会收到任何请求。
如果您想在测试用例中接收来自该服务器组件的请求,请删除调度响应适配器和静态响应适配器。
刚抽出时间来分享我的解决方案。首先 - 有一个 post (http://citrus.895196.n3.nabble.com/Citrus-to-act-as-a-mock-server-td4023066.html) 告诉我们,"What you need is a standalone simulator that waits for incoming requests and sends pre-defined response messages. This is not the primary focus of Citrus as a test framework."。但我找到了解决方法:
1) 使用全局变量作为标志告诉我们,异步请求是否从 SUT 到达:
Spring 上下文:
<bean id="globalVariables" class="com.consol.citrus.variables.GlobalVariables"></bean>
Java代码:
@Autowired
private GlobalVariables globalVariables
并在开始等待 SUT 异步回调请求之前设置变量(标志)
globalVariables.getVariables().put("SUTcallbackStatus", "waiting");
2) 扩展 IteratingConditionExpression
- 重写 evaluate
方法,如下所示:
@Override
public boolean evaluate(int index, TestContext context) {
if(index > threshold){
testToFail.fail("The async message didn't arrived to the mock server.");
return false;
}
if(globalVariables.getVariables().get("SUTcallbackStatus").equals("received")){
return false;
}
return true;
}
上面代码中的 testToFail
和 threshold
变量应该从测试中设置 class:
myIteratingConditionExpression.setThreshold(50);
myIteratingConditionExpression.setTestToFail(this);
它允许您控制测试应等待响应的时间(threshold
*0.5
秒)并允许您指向测试,如果未收到回调则应失败假定期间的响应。
3) 扩展 StaticResponseEndpointAdapter
- 重写下面的方法
@Override
public Message handleMessageInternal(Message message) {
globalVariables.getVariables().put("SUTcallbackStatus", "received");
return super.handleMessageInternal(message);
}
并将此适配器用作您的模拟服务适配器:
<citrus-http:server id="asyncResponseMockService"
port="${server.callback.port}"
auto-start="true"
timeout="10000"
endpoint-adapter="myResponseAdapter" />
4) 然后,在您的测试中 class - 开始等待异步回调请求 - 只需使用带有自定义迭代条件表达式的 iterate
操作:
iterate(sleep(0.5)).condition(myIteratingConditionExpression);
这对我有用:)