Unit testing the API

We write a basic test case in the io.vertx.guides.wiki.http.ApiTest class.

The preamble consists in preparing the test environment. The HTTP server verticle needs the database verticle to be running, so we need to deploy both in our test Vert.x context:

  1. @RunWith(VertxUnitRunner.class)
  2. public class ApiTest {
  3. private Vertx vertx;
  4. private WebClient webClient;
  5. @Before
  6. public void prepare(TestContext context) {
  7. vertx = Vertx.vertx();
  8. JsonObject dbConf = new JsonObject()
  9. .put(WikiDatabaseVerticle.CONFIG_WIKIDB_JDBC_URL, "jdbc:hsqldb:mem:testdb;shutdown=true") (1)
  10. .put(WikiDatabaseVerticle.CONFIG_WIKIDB_JDBC_MAX_POOL_SIZE, 4);
  11. vertx.deployVerticle(new WikiDatabaseVerticle(),
  12. new DeploymentOptions().setConfig(dbConf), context.asyncAssertSuccess());
  13. vertx.deployVerticle(new HttpServerVerticle(), context.asyncAssertSuccess());
  14. webClient = WebClient.create(vertx, new WebClientOptions()
  15. .setDefaultHost("localhost")
  16. .setDefaultPort(8080));
  17. }
  18. @After
  19. public void finish(TestContext context) {
  20. vertx.close(context.asyncAssertSuccess());
  21. }
  22. // (...)
  1. We use a different JDBC URL to use an in-memory database for the tests.

The proper test case is a simple scenario where all types of requests are being made. It creates a page, fetches it, updates it then deletes it:

  1. @Test
  2. public void play_with_api(TestContext context) {
  3. Async async = context.async();
  4. JsonObject page = new JsonObject()
  5. .put("name", "Sample")
  6. .put("markdown", "# A page");
  7. Promise<HttpResponse<JsonObject>> postPagePromise = Promise.promise();
  8. webClient.post("/api/pages")
  9. .as(BodyCodec.jsonObject())
  10. .sendJsonObject(page, postPagePromise);
  11. Future<HttpResponse<JsonObject>> getPageFuture = postPagePromise.future().compose(resp -> {
  12. Promise<HttpResponse<JsonObject>> promise = Promise.promise();
  13. webClient.get("/api/pages")
  14. .as(BodyCodec.jsonObject())
  15. .send(promise);
  16. return promise.future();
  17. });
  18. Future<HttpResponse<JsonObject>> updatePageFuture = getPageFuture.compose(resp -> {
  19. JsonArray array = resp.body().getJsonArray("pages");
  20. context.assertEquals(1, array.size());
  21. context.assertEquals(0, array.getJsonObject(0).getInteger("id"));
  22. Promise<HttpResponse<JsonObject>> promise = Promise.promise();
  23. JsonObject data = new JsonObject()
  24. .put("id", 0)
  25. .put("markdown", "Oh Yeah!");
  26. webClient.put("/api/pages/0")
  27. .as(BodyCodec.jsonObject())
  28. .sendJsonObject(data, promise);
  29. return promise.future();
  30. });
  31. Future<HttpResponse<JsonObject>> deletePageFuture = updatePageFuture.compose(resp -> {
  32. context.assertTrue(resp.body().getBoolean("success"));
  33. Promise<HttpResponse<JsonObject>> promise = Promise.promise();
  34. webClient.delete("/api/pages/0")
  35. .as(BodyCodec.jsonObject())
  36. .send(promise);
  37. return promise.future();
  38. });
  39. deletePageFuture.setHandler(ar -> {
  40. if (ar.succeeded()) {
  41. context.assertTrue(ar.result().body().getBoolean("success"));
  42. async.complete();
  43. } else {
  44. context.fail(ar.cause());
  45. }
  46. });
  47. async.awaitSuccess(5000);
  48. }
Tip
The test uses Future objects composition rather than nested callbacks; the last composition must complete the async future or the test will eventually time out.