Webtau - can TableData be used in a JUnit test to verify that a REST response JSON contains all given entries?

51 Views Asked by At

Webtau offers, among other things, some very expressive shortcuts, like TableData. I'm currently using that with JUnit. E.g. for testing expected data from a REST endpoint e.g.:

[
  { "uuid": "1-2-3-4", "directionShort": "N", "direction": "North" },
  { "uuid": "1-2-3-5", "directionShort": "S", "direction": "South" },
  { "uuid": "1-2-3-6", "directionShort": "E", "direction": "East" },
  { "uuid": "1-2-3-7", "directionShort": "W", "direction": "West" }
]

I could write something like (yes, of course this example is a bit exagerated):

import static org.assertj.core.api.Assertions.assertThat;
import static org.testingisdocumenting.webtau.WebTauDsl.http;
import static org.testingisdocumenting.webtau.Matchers.equal;
import static org.testingisdocumenting.webtau.WebTauCore.table;
import static org.testingisdocumenting.webtau.WebTauCore.____________;

http.get(URL_CARDINAL_POINTS,
    (header, body) -> {
        header.get("statusCode").shouldBe(equal(200));
        assertThat(body.isList()).isTrue();
        assertThat(body.numberOfElements()).isEqualTo(4);

        body.should(equal(table(
            "*directionShort", "direction",
            ____________,
            "N", "North",
            "S", "South",
            "E", "East",
            "W", "West"
          )));
    }
);

That's practicable for small sets of values. For larger data sets I'd like to test with containAll like e.g. this:

[
  { "uuid": "...", "name": "Stockholm", "country": "Sweden", "population": 10.42 },
  { "uuid": "...", "name": "Kiew", "country": "Ukraine", "population": 10.42 },
  ...
]
import static org.testingisdocumenting.webtau.Matchers.containAll;

http.get(URL_CAPITAL_CITIES,
    (header, body) -> {
        header.get("statusCode").shouldBe(equal(200));
        assertThat(body.isList()).isTrue();
        assertThat(body.numberOfElements()).isGreaterThan(10);

        body.should(containAll(table(
            "*name", "country", "population",
            ________________________________,
            "Paris", "France", 2.161,
            "Berlin", "Germany", 3.645,
            "Kiew", "Ukraine", 2.884,
            "Oslo", "Norway", 0.634,
            "Madrid", "Spain", 3.223
          )));
    }
);

What I tried:

But that doesn't work, it fails with: IllegalArgumentException: column 'name' is not present.

When leaving out the key column marker (the * in front of "name" column), the error changes to:

    body.should(containAll(table("name", "country", [...])
      -->
    "expecting body to contain all [<the table>]: no matches found for [<the table>]"

When using contain() instead of containAll:

    body.should(contain(table("name", "country", [...])
      -->
    "AssertionError: no match found"

Ugly solution:

Check "manually" for matches:

    Object dataNode;
    dataNode = body.find(it -> "Paris".equals(it.get("name").get()));
    assertThat(dataNode).isNotNull();
    dataNode = body.find(it -> "Kiew".equals(it.get("name").get()));
    assertThat(dataNode).isNotNull();
    dataNode = body.find(it -> "Oslo".equals(it.get("name").get()));
    assertThat(dataNode).isNotNull();
    ...

which is very tedious when trying to compare more attributes other then the "key".

Still... ugly solution:

Still far away from the expressiveness of table, because the keys clutter the data:

import static org.testingisdocumenting.webtau.utils.CollectionUtils.map;

    body.should(containAll(
        map("name", "Paris", "country", "France", "population": 2.161),
        map("name", "Berlin", "country", "Germany", "population": 3.645),
        map("name", "Kiew", "country", "Ukraine", "population": 2.884),
        map("name", "Oslo", "country", "Norway", "population": 0.634),
        map("name", "Madrid", "country", "Spain", "population": 3.223)
    ));

Question:

Is there a way to use DataTable table instead of the map sequence?

  body.should(containAll(table(
      "*name", "country", "population",
      ________________________________,
      "Paris", "France", 2.161,
      "Berlin", "Germany", 3.645,
      "Kiew", "Ukraine", 2.884,
      "Oslo", "Norway", 0.634,
      "Madrid", "Spain", 3.223
  )));
1

There are 1 best solutions below

1
Mykola Golubyev On

I think it is a good suggestion! I will have to add a new rule to WebTau to make it work. I understand the intent and it makes sense.

Syntax will be

body.should(contain(table))

This is now released: https://testingisdocumenting.org/webtau/HTTP/matchers#contain-table

Also super glad you are using table! Feel free to join discord server, I would love to learn more about your experience, ideas and feedback.