"Wiremock" for 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 合約,因此您可以在本機或在與伺服器共用的測試庫中設定這些合約。 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,則回應是單值的。 如果框架類型為 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 相同,只是每次從輸入串流接收到訊息時,都會再次發出輸出串流。

操作和檢查訊息目錄

如果您需要更靈活的處理規則,您可以從介面中方便的靜態 factory 方法建立自己的 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 社群中所有即將到來的活動。

查看全部