"Wiremock" 用于 RSocket

工程 | Dave Syer | 2021年6月2日 | ...

如果您的应用程序在运行时连接到 RSocket 服务器,您如何测试它?我们需要一种方法让测试启动服务器并告诉我们它正在侦听的位置,然后我们需要能够注册请求和响应示例(也就是“合约”)。这就是这个 项目 提供的功能 - 它就像 Wiremock,但用于 RSocket。

开始使用

使用该项目最简单的方法是作为 JUnit (Jupiter) 扩展,例如

@SpringBootTest
@ExtendWith(RSocketServerExtension.class)
class SocketsApplicationTests {
	...
}

安装此扩展后,Spring Boot 测试将在 RSocket 服务器上运行,该服务器监听由 test.rsocket.server.port 给出的端口,因此测试可以直接连接到它,或者(更可能)它正在测试的代码将连接到它。您可能需要通过 @SpringBootTest 注释告诉它连接的位置,例如,如果应用程序在运行时查找名为 rsocket.port 的属性

@SpringBootTest("rsocket.port=${test.rsocket.server.port}")
@ExtendWith(RSocketServerExtension.class)
class SocketsApplicationTests {
	...
}

在 JSON 中定义消息映射

测试方法可以注入 RSocketMessageCatalogRSocketMessageRegistry,然后使用它们来设置或检查服务器的状态。默认情况下,服务器从类路径下的 /catalog/*.json 读取 JSON 合约,因此您可以在本地或与 sarver 共享的测试库中设置这些合约。JSON 的结构镜像存储在 RSocketMessageCatalog 中的 MessageMapping。这是一个例子(请求和响应只是 JSON 对象)

{
	"pattern": "events.response.*",
	"frameType": "REQUEST_RESPONSE",
	"request": {
		"origin": "Client"
	},
	"response": {
		"origin": "Server",
		"interaction": "Response",
		"index": 0
	}
}

此映射将匹配路由上与模式匹配的任何 REQUEST_RESPONSE 帧类型,并且该路由还具有一个 "origin" 字段等于 "Client" 的请求。您还可以通过添加通配符来匹配请求中字段的模式。或者您可以省略请求仅匹配路由。如果帧类型是 REQUEST_RESPONSE,则响应是单值的。如果 frametype 是 REQUEST_STREAM,您可以提供多值 "responses",例如

{
	"pattern": "my.stream.route",
	"frameType": "REQUEST_STREAM",
	"responses": [
		{
			"origin": "Server",
			"interaction": "Stream",
			"index": 0
		},
		{
			"origin": "Server",
			"interaction": "Stream",
			"index": 1
		},
		{
			"origin": "Server",
			"interaction": "Stream",
			"index": 2
		}
	]
}

此外,您可以指定一个整数字段 "repeat" 来重复响应以形成更长的流。如果帧类型是 REQUEST_FNF,则没有响应,并且请求将被忽略。最后,如果帧类型是 REQUEST_CHANNEL,则映射 JSON 的格式与 REQUEST_STREAM 相同,不同之处在于每次从输入流中收到消息时,都会再次发出输出流。

操作和检查消息目录

如果您的处理规则需要更大的灵活性,您可以从接口中方便的静态工厂方法创建自己的 MessageMapping。您可以提供一个处理函数(除了 fire and forget 的情况),一个要匹配的模式,以及可选的要匹配的请求。这些方法可以用于动态注册映射以定义服务器在运行时的预期行为。

您可以通过从目录中获取 MessageMapping 来检查服务器的状态,然后调用其中一个 drain() 方法来耗尽已收到的请求。例如

@SpringBootTest
@ExtendWith(RSocketServerExtension.class)
class DynamicRouteTests {

	private RSocketRequester rsocketRequester;

	public DynamicRouteTests(@Autowired RSocketRequester.Builder rsocketRequesterBuilder,
			@Value("${test.rsocket.server.port:7000}") int port) {
		rsocketRequester = rsocketRequesterBuilder.tcp("localhost", port);
	}

	@Test
	void response(RSocketMessageRegistry catalog) {
		MessageMapping response = MessageMapping.response("response")
				.response(new Foo("Server", "Response"));
		catalog.register(response);
		assertThat(rsocketRequester.route("response").data(new Foo("Client", "Request"))
				.retrieveMono(Foo.class).doOnNext(foo -> {
					System.err.println(foo);
					assertThat(foo.getOrigin()).isEqualTo("Server");
				}).block()).isNotNull();
		assertThat(response.drain()).hasSize(1);
		assertThat(response.drain()).hasSize(0);
	}

}

这里的代码仍然是一个原型,但它已经可能非常有用。所以试试看并发送反馈,也许我们可以让它成熟到我们可以发布它的程度。

获取 Spring 新闻资讯

通过 Spring 新闻资讯保持联系

订阅

先人一步

VMware 提供培训和认证,以加速您的进步。

了解更多

获得支持

Tanzu Spring 在一个简单的订阅中提供对 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部