如何访问(柑橘类)静态响应适配器中的变量
How to access variables in a (citrus) static-response-adapter
跟进
我正在使用 Citrus 2.7,我的测试扩展了 TestNGCitrusTestRunner:
@Test
@CitrusTest
public void testRequestOk() {
variable("myTest", "baz");
http(builder -> builder
.client("fooClient")
.send()
.post("/foo/bar")
.payload(new ClassPathResource("/foo/bar-baz.xml"))
.messageType(MessageType.XML)
.contentType("application/xml")
.accept("application/xml"));
http(builder -> builder
.client("fooClient")
.receive()
.response(HttpStatus.OK)
.validate("foo.bar", "baz"));
}
请求被发送到 SUT,这反过来触发对 Citrus 的两个 http 调用(对 mockOne 和 mockTwo)。
使用以下配置:
<citrus-http:server id="mockOne"
port="9090"
auto-start="true"
endpoint-adapter="staticResponseAdapter"
security-handler="securityHandlerOne"/>
<citrus-http:server id="mockTwo"
port="9080"
auto-start="true"
endpoint-adapter="dispatchingEndpointAdapter"
security-handler="securityHandlerTwo"/>
...
<citrus:static-response-adapter id="staticResponseAdapter">
<citrus:payload>
<![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<foo>
<bar>${myTest}</bar>
</foo>
]]>
</citrus:payload>
</citrus:static-response-adapter>
我收到:com.consol.citrus.exceptions.CitrusRuntimeException: Unknown variable 'myTest'
在日志中,我看到最初设置了变量:
15:02:48,696 DEBUG citrus.Citrus| TEST STEP 1: create-variables
15:02:48,697 INFO reateVariablesAction| Setting variable: myTest to value: foo
15:02:48,697 DEBUG context.TestContext| Setting variable: myTest with value: 'foo'
但就在应该进行变量替换之前,Citrus 会这样做:
15:02:49,281 DEBUG ngHandlerInterceptor| Received Http request:
...
15:02:49,297 DEBUG t.TestContextFactory| Created new test context - using global variables: '{}'
15:02:49,299 DEBUG rusDispatcherServlet| Could not complete request
com.consol.citrus.exceptions.CitrusRuntimeException: Unknown variable 'myTest'
我是不是做错了什么或者这是预期的行为?
这是预期的行为,因为静态响应适配器会创建自己的测试上下文。您可以在日志中看到
15:02:49,297 DEBUG t.TestContextFactory| Created new test context - using global variables: '{}'
所以一般来说,静态响应适配器无法访问您的测试实例的测试变量。这仅仅是因为传入请求与您的 运行 测试没有可能的关联。这就是 "static" 响应适配器中 "static" 响应的描述。
如果您想获得更多动态响应消息,您应该在测试中包含服务器通信 http(builder -> builder.server("mockOne").receive())
和 http(builder -> builder.server("mockOne").send().response())
。
您可以使用测试行为 (http://www.citrusframework.org/reference/html/behaviors.html) 而不是静态响应适配器。这样您就可以定义一次服务器通信并在多个测试中使用它。
public class MockOneServerBehavior extends AbstractTestBehavior {
public void apply() {
http(builder -> builder.server("mockOne")
.receive()
.post());
http(builder -> builder.server("mockOne")
.send()
.response()
.payload("<foo><bar>${myTest}</bar></foo>"));
}
}
行为 能够访问测试的测试变量,因为行为在您的测试中得到明确应用。
@Test
@CitrusTest
public void testRequestOk() {
variable("myTest", "baz");
http(builder -> builder
.client("fooClient")
.send()
.post("/foo/bar")
.payload(new ClassPathResource("/foo/bar-baz.xml"))
.messageType(MessageType.XML)
.contentType("application/xml")
.accept("application/xml"))
.fork(true);
MockOneServerBehavior mockOneBehavior = new MockOneServerBehavior();
applyBehavior(mockOneBehavior);
http(builder -> builder
.client("fooClient")
.receive()
.response(HttpStatus.OK)
.validate("foo.bar", "baz"));
}
请注意,我在 http 客户端发送操作中添加了 fork 选项。这是因为 Http 协议本质上是同步的,Citrus 同时充当客户端和服务器。
跟进
我正在使用 Citrus 2.7,我的测试扩展了 TestNGCitrusTestRunner:
@Test
@CitrusTest
public void testRequestOk() {
variable("myTest", "baz");
http(builder -> builder
.client("fooClient")
.send()
.post("/foo/bar")
.payload(new ClassPathResource("/foo/bar-baz.xml"))
.messageType(MessageType.XML)
.contentType("application/xml")
.accept("application/xml"));
http(builder -> builder
.client("fooClient")
.receive()
.response(HttpStatus.OK)
.validate("foo.bar", "baz"));
}
请求被发送到 SUT,这反过来触发对 Citrus 的两个 http 调用(对 mockOne 和 mockTwo)。
使用以下配置:
<citrus-http:server id="mockOne"
port="9090"
auto-start="true"
endpoint-adapter="staticResponseAdapter"
security-handler="securityHandlerOne"/>
<citrus-http:server id="mockTwo"
port="9080"
auto-start="true"
endpoint-adapter="dispatchingEndpointAdapter"
security-handler="securityHandlerTwo"/>
...
<citrus:static-response-adapter id="staticResponseAdapter">
<citrus:payload>
<![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<foo>
<bar>${myTest}</bar>
</foo>
]]>
</citrus:payload>
</citrus:static-response-adapter>
我收到:com.consol.citrus.exceptions.CitrusRuntimeException: Unknown variable 'myTest'
在日志中,我看到最初设置了变量:
15:02:48,696 DEBUG citrus.Citrus| TEST STEP 1: create-variables
15:02:48,697 INFO reateVariablesAction| Setting variable: myTest to value: foo
15:02:48,697 DEBUG context.TestContext| Setting variable: myTest with value: 'foo'
但就在应该进行变量替换之前,Citrus 会这样做:
15:02:49,281 DEBUG ngHandlerInterceptor| Received Http request:
...
15:02:49,297 DEBUG t.TestContextFactory| Created new test context - using global variables: '{}'
15:02:49,299 DEBUG rusDispatcherServlet| Could not complete request
com.consol.citrus.exceptions.CitrusRuntimeException: Unknown variable 'myTest'
我是不是做错了什么或者这是预期的行为?
这是预期的行为,因为静态响应适配器会创建自己的测试上下文。您可以在日志中看到
15:02:49,297 DEBUG t.TestContextFactory| Created new test context - using global variables: '{}'
所以一般来说,静态响应适配器无法访问您的测试实例的测试变量。这仅仅是因为传入请求与您的 运行 测试没有可能的关联。这就是 "static" 响应适配器中 "static" 响应的描述。
如果您想获得更多动态响应消息,您应该在测试中包含服务器通信 http(builder -> builder.server("mockOne").receive())
和 http(builder -> builder.server("mockOne").send().response())
。
您可以使用测试行为 (http://www.citrusframework.org/reference/html/behaviors.html) 而不是静态响应适配器。这样您就可以定义一次服务器通信并在多个测试中使用它。
public class MockOneServerBehavior extends AbstractTestBehavior {
public void apply() {
http(builder -> builder.server("mockOne")
.receive()
.post());
http(builder -> builder.server("mockOne")
.send()
.response()
.payload("<foo><bar>${myTest}</bar></foo>"));
}
}
行为 能够访问测试的测试变量,因为行为在您的测试中得到明确应用。
@Test
@CitrusTest
public void testRequestOk() {
variable("myTest", "baz");
http(builder -> builder
.client("fooClient")
.send()
.post("/foo/bar")
.payload(new ClassPathResource("/foo/bar-baz.xml"))
.messageType(MessageType.XML)
.contentType("application/xml")
.accept("application/xml"))
.fork(true);
MockOneServerBehavior mockOneBehavior = new MockOneServerBehavior();
applyBehavior(mockOneBehavior);
http(builder -> builder
.client("fooClient")
.receive()
.response(HttpStatus.OK)
.validate("foo.bar", "baz"));
}
请注意,我在 http 客户端发送操作中添加了 fork 选项。这是因为 Http 协议本质上是同步的,Citrus 同时充当客户端和服务器。