更进一步
VMware 提供培训和认证,助你加速进步。
了解更多阅读时长:约 6 分钟 编码时长:约 15 分钟
如果你一直在关注本系列文章,那么现在你已经构建了一个 Spring Boot 原型,它展示了 RSocket 中的许多特性。然而,这段代码并非生产级代码;它只是一个原型,是你在 RSocket 之旅中的一块垫脚石。对于生产级代码,我期望遵循所有常规的质量保证和测试规则。因此,在本练习中,我将向你展示如何为 RSocket 响应器编写集成测试,从而让你离生产环境更进一步。
但首先,我说的集成测试是什么意思?
在此上下文中,集成测试是指测试 RSocket 请求者和响应者之间的来回通信。在这种测试期间,重要的是要验证架构的每一层,包括网络层。
但是,集成测试可能比常规单元测试更耗时,正是因为你需要验证每一层。它们运行时间可能更长,需要多个组件和层,并且可预测性较低。然而,集成测试还有其他好处,例如检查你的请求者和响应者是否彼此建立连接并正常通信。
你还会注意到,在本教程中我跳过了所有其他形式的测试。要涵盖所有可能的测试类型需要写一整本书!如果你正在寻找 Spring Boot 应用程序测试的更通用介绍,可以看看 Andy Wilkinson 的这段演讲,或者Spring Boot 测试文档,或者在线搜索“testing spring applications”。
背景介绍到此为止;让我们开始测试吧!
如果你需要查看代码,可以在 GitHub 上找到。如果你想回顾本系列的其他文章,它们都列在 Spring 网站上我的页面上。
在你的 rsocket-server
项目中,在 /src/test/java/io/pivotal/rsocketserver/
文件夹下,创建一个新的集成测试类,名为 RSocketClientToServerITest
。最简单的方法通常是在你的 IDE 中完成。
建议的命名约定是让每个集成测试类名以后缀 'ITest' 结尾。生成的文件名 <your-class-name>ITest.java
更易于阅读,并允许 Maven 过滤你的集成测试——这是你稍后会使用的一种技术。请务必使用 @SpringBootTest
注解你的新类,如下所示
@SpringBootTest
public class RSocketClientToServerITest {
// test code goes here
}
@SpringBootTest
注解允许 Spring Boot 为你的测试配置所有必需的内容,包括 RSocket。这节省了大量时间和配置工作。
你可以使用一个 RSocket 连接进行多次测试,方法是将 RSocketRequester
添加为全局类变量,如下所示
private static RSocketRequester requester;
在运行测试之前,你必须为这个请求者建立一个工作连接。JUnit5 的 @BeforeAll
注解非常适合执行这些一次性的设置任务。将以下方法添加到你的类中
@BeforeAll
public static void setupOnce(@Autowired RSocketRequester.Builder builder, @Value("${spring.rsocket.server.port}") Integer port) {
requester = builder
.connectTcp("localhost", port)
.block();
}
你会注意到该方法签名期望 Spring Boot 从 Spring 应用程序上下文中传递一些项目。RSocketRequester.Builder
简化了 RSocket 连接的创建,而要建立连接则需要响应器的端口号。该端口号来自 application.properties
文件中的 spring.rsocket.server.port
值。
现在请求者已就绪;你就可以添加第一个集成测试了。此测试期间会发生两件事。首先,从请求者向响应者发起调用,并附加了命名路由和数据。其次,验证接收到的响应是否完全符合预期。代码如下所示
@Test
public void testRequestGetsResponse() {
// Send a request message (1)
Mono<Message> result = requester
.route("request-response")
.data(new Message("TEST", "Request"))
.retrieveMono(Message.class);
// Verify that the response message contains the expected data (2)
StepVerifier
.create(result)
.consumeNextWith(message -> {
assertThat(message.getOrigin()).isEqualTo(RSocketController.SERVER); assertThat(message.getInteraction()).isEqualTo(RSocketController.RESPONSE);
assertThat(message.getIndex()).isEqualTo(0);})
.verifyComplete();
}
在第一部分(1)中,使用的路由是 "request-response"
,数据是一个新的 Message
对象。从响应者(你的 RSocketController)返回的结果是一个 Message
类型的 Mono
。
在第二部分(2)中,StepVerifier 类检查 mono 是否符合预期。在 consumeWithNext()
方法中,一个函数使用 AssertJ 的断言方法检查返回消息的内容。verifyComplete()
方法确保交互按预期完成。
其他交互类型的测试也是以相同的方式进行的。与其在此描述每种交互类型的测试,不如查看 GitHub 上的完整测试代码。
测试周期完成后,你可以关闭所有不再需要的资源。在这种情况下,这意味着释放 RSocket 请求者。添加一个方法来执行此操作,并使用 @AfterAll
注解该方法,如下所示
@AfterAll
public static void tearDownOnce() {
requester.rsocket().dispose();
}
运行集成测试可能需要一些时间,并且可能由于意外原因(例如网络中断)而失败。因此,隔离你的集成测试以便选择性运行它们是有意义的。Maven 使用 Failsafe 插件来实现这一目标。
要配置 failsafe,在你的 pom.xml
中添加以下插件配置。此配置告知 Maven 使用 failsafe 来运行所有以 'ITest.java' 为后缀的测试。它还告知 Maven 将这些测试作为 integration-test
或 verify
生命周期阶段的一部分来运行。
<plugins>
<!-- other plugins -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.0</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<includes>**/*ITest.java</includes>
</configuration>
</plugin>
你还会希望阻止集成测试与常规单元测试一起运行,因此添加以下 surefire 配置来排除它们
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/*ITest.java</exclude>
</excludes>
</configuration>
</plugin>
<!-- other plugins -->
</plugins>
你现在可以在终端控制台中运行你的集成测试。Maven 使用 integration-test
目标来实现此目的。
./mvnw clean integration-test
Maven 现在会运行你的集成测试,结果将显示在控制台中。
[INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 23.582 s - in io.pivotal.rsocketserver.RSocketClientToServerITest
2020-05-19 10:43:27.512 INFO 39250 --- [extShutdownHook] i.p.rsocketserver.RSocketController : Detaching all remaining clients...
2020-05-19 10:43:27.513 INFO 39250 --- [extShutdownHook] i.p.rsocketserver.RSocketController : Shutting down.
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
你也可以对客户端的响应器进行集成测试。所需代码比上面的代码稍微复杂一些。主要包括创建一个伪请求者组件,该组件包含与此处所见的类似的 StepVerifier
测试。与其逐行描述代码,我建议你直接查看源代码。
集成测试是走向生产环境的关键组成部分。通过以这种方式测试你的 RSocket 响应器,你可以防止回归,检查组件是否正常通信,并更有信心地将它们交付给客户。