感兴趣的朋友,可以关注微信服务号“猿学堂社区”,或加入“猿学堂社区”微信交流群
版权声明:本文由作者自行翻译,未经作者授权,不得随意转发。
到目前为止,我们已经开发了未包含测试的Wiki实现。这自然不是一种好的实践,因此让我们看一下如何为Vert.x代码编写测试。
5.1 开始
vertx-unit模块提供了工具来测试Vert.x中的异步操作。除此之外,你还可以使用你选择的测试框架,如JUnit。
使用JUnit,需要的Maven依赖如下:
junit
junit
4.12
test
io.vertx
vertx-unit
test
JUnit测试需要注解为VertxUnitRunner runner,以便使用vertx-unit特性:
@RunWith(VertxUnitRunner.class)
public class SomeTest {
// (...)
}
通过这个runner,JUnit测试和生命周期方法接收一个TestContext参数。这个对象提供了对基础断言、存储数据上下文的访问,以及几个面向异步的帮助类,我们将在本节中可以看到。
为了说明它,让我们考虑一个异步场景,我们想要检查一个timer任务被调用了一次,以及一个周期任务被调用了三次。由于这个代码是异步的,所以测试方法在测试完成之前就退出,因此,使测试通过或失败还需要以异步方式进行:
@Test /*(timeout=5000)*/ ⑧
public void async_behavior(TestContext context) { ①
Vertx vertx = Vertx.vertx(); ②
context.assertEquals("foo", "foo"); ③
Async a1 = context.async(); ④
Async a2 = context.async(3); ⑤
vertx.setTimer(100, n -> a1.complete()); ⑥
vertx.setPeriodic(100, n -> a2.countDown()); ⑦
}
① TestContext是由runner提供的一个参数。
② 由于我们在单元测试中,我们需要创建一个Vert.x上下文。
③ 此处是一个基本的TestContext断言的示例。
④ 我们得到第一个Async对象,它接下来可能完成(或失败)。
⑤ 这个Async对象作为一个countdown工作,在三次调用之后成功完成。
⑥ 我们在timer触发时完成。
⑦ 每次周期任务触发一个countdown。测试在所有Async对象完成后通过。
⑧ 有一个默认(long)超时时间用于异步测试用例,但是它可以通过JUnit的@Test注解覆盖。
5.2 测试数据库操作
数据库服务非常适合编写测试。
我们首先需要部署数据库Verticle。我们将配置JDBC链接为HSQLDB,使用内存存储,当成功的时候,我们将获取一个服务代理用于我们的测试用例。
由于这些操作的需要,我们利用JUnit的before/after生命周期方法:
private Vertx vertx;
private WikiDatabaseService service;
@Before
public void prepare(TestContext context) throws InterruptedException {
vertx = Vertx.vertx();
JsonObject conf = new JsonObject() ①
.put(WikiDatabaseVerticle.CONFIG_WIKIDB_JDBC_URL, "jdbc:hsqldb:mem:testdb;shutdown=true")
.put(WikiDatabaseVerticle.CONFIG_WIKIDB_JDBC_MAX_POOL_SIZE, 4);
vertx.deployVerticle(new WikiDatabaseVerticle(), new DeploymentOptions().setConfig(conf),
context.asyncAssertSuccess(id -> ②
service = WikiDatabaseService.createProxy(vertx,WikiDatabaseVerticle.CONFIG_WIKIDB_QUEUE)));
}
① 我们只是复写了Verticle的部分配置,其它使用默认值。
② asyncAssertSuccess对于提供一个检测异步操作成功的handler是非常有用的。它有一个变体是无参的,另一个变体像这个,此时我们可以链接结果到另一个handler。
Vert.x的清理很简单,我们再次使用asyncAssertSuccess以确保没有遇到错误:
@After
public void finish(TestContext context) {
vertx.close(context.asyncAssertSuccess());
}
数据库服务的操作本质上是CRUD操作,因此使用一个JUnit测试用例合并它们全部是一个测试的好方法:
@Test
public void crud_operations(TestContext context) {
Async async = context.async();
service.createPage("Test","Some content",context.asyncAssertSuccess(v1 -> {
service.fetchPage("Test",context.asyncAssertSuccess(json1 -> {
context.assertTrue(json1.getBoolean("found"));
context.assertTrue(json1.containsKey("id"));
context.assertEquals("Some content",json1.getString("rawContent"));
service.savePage(json1.getInteger("id"),"Yo!",context.asyncAssertSuccess(v2 -> {
service.fetchAllPages(context.asyncAssertSuccess(array1 -> {
context.assertEquals(1,array1.size());
service.fetchPage("Test",context.asyncAssertSuccess(json2 -> {
context.assertEquals("Yo!",json2.getString("rawContent"));
service.deletePage(json1.getInteger("id"),v3 -> {
service.fetchAllPages(context.asyncAssertSuccess(array2 -> {
context.assertTrue(array2.isEmpty());
async.complete();①
}));
});
}));
}));
}));
}));
}));
async.awaitSuccess(5000);②
}
① 这是唯一的Async最终完成的地方。
② 这是在退出测试用例方法和依赖JUnit超时之间的取舍。此处,测试用例线程执行等待直到Async完成或者超时周期过去。