Single Test Method

We have an app that exposes create , read , update , and delete operations for customer records. Records are being served under /customers .Here is an example of a CRUD operations test. Groovy package scenarios.rest.springboot import static org.testingisdocumenting.webtau.WebTauGroovyDsl.* scenario("CRUD operations for customer") { def customerPayload = [firstName: "FN", lastName: "LN"] // new customer data def id = http.post("/customers", customerPayload) { return id // return id value from response body } http.get("/customers/${id}") { body.should == customerPayload // only specified properties will be asserted against } def changedLastName = "NLN" http.put("/customers/${id}", [*:customerPayload, lastName: changedLastName]) { lastName.should == changedLastName // specifying body is optional } http.get("/customers/${id}") { firstName.should == "FN" lastName.should == changedLastName } def changedFirstName = "NFN" http.patch("/customers/${id}", [firstName: changedFirstName]) http.get("/customers/${id}") { firstName.should == changedFirstName lastName.should == changedLastName } http.delete("/customers/${id}") { statusCode.should == 204 } http.get("/customers/${id}") { statusCode.should == 404 } } Check HTTP/import-and-dependencies Import And Dependencies for prerequisites. Java package com.example.tests.junit5; import org.junit.jupiter.api.Test; import org.testingisdocumenting.webtau.junit5.WebTau; import static org.testingisdocumenting.webtau.WebTauDsl.*; @WebTau public class CustomerCrudJavaTest { @Test public void crud() { var customerPayload = http.json( // new customer data "firstName", "FN", "lastName", "LN"); int id = http.post("/customers", customerPayload, ((header, body) -> { return body.get("id"); // return id value from response body })); http.get("/customers/" + id, ((header, body) -> { body.should(equal(customerPayload)); // only specified properties will be asserted against })); String changedLastName = "NLN"; var changedCustomerPayload = http.json( "firstName", "FN", "lastName", "NLN"); http.put("/customers/" + id, changedCustomerPayload, ((header, body) -> { body.get("firstName").should(equal("FN")); body.get("lastName").should(equal(changedLastName)); })); http.get("/customers/" + id, ((header, body) -> { body.should(equal(changedCustomerPayload)); })); http.delete("/customers/" + id, ((header, body) -> { header.statusCode.should(equal(204)); })); http.get("/customers/" + id, ((header, body) -> { header.statusCode.should(equal(404)); })); } } Check HTTP/import-and-dependencies Import And Dependencies for prerequisites.

Generated Report

After test runs, WebTau generates report/introduction HTML report:Note: asserted values are being tracked and highlighted inside the report

Separate Test Methods

Groovy One of the benefits of separating one CRUD scenario into multiple is to be able to run one test at a time. In order to make each test runnable independently we will use createLazyResource . package scenarios.rest.springboot import static org.testingisdocumenting.webtau.WebTauGroovyDsl.* def customerPayload = [firstName: "FN", lastName: "LN"] def customer = createLazyResource("customer") { // lazy resource to be created on the first access def id = http.post("/customers", customerPayload) { return id } return new Customer(id: id, url: "/customers/${id}") // definition is below } scenario("customer create") { customer.id.should != null // accessing resource for the first time will trigger POST (in this example) } scenario("customer read") { http.get(customer.url) { // convenient re-use of url defined above body.should == customerPayload } } scenario("customer update") { def changedLastName = "NLN" http.put(customer.url, [*:customerPayload, lastName: changedLastName]) { lastName.should == changedLastName } http.get(customer.url) { lastName.should == changedLastName } } scenario("customer delete") { http.delete(customer.url) { statusCode.should == 204 } http.get(customer.url) { statusCode.should == 404 } } package scenarios.rest.springboot class Customer { Number id String url // store url of the created entity } Note: to run one scenario at a time use sscenario (additional s in front). groovy-standalone-runner/selective-run Read more Java One of the benefits of separating one CRUD @Test into multiple is to be able to run one test at a time. In order to make each test runnable independently we will leverage BeforeAll , AfterAll , and TestMethodOrder . package com.example.tests.junit5; import org.testingisdocumenting.webtau.http.request.HttpRequestBody; import org.testingisdocumenting.webtau.junit5.WebTau; import org.junit.jupiter.api.*; import static org.testingisdocumenting.webtau.WebTauDsl.*; @WebTau // annotation to enable rich console output and html reporting @TestMethodOrder(MethodOrderer.OrderAnnotation.class) // forcing methods execution order @DisplayName("customer CRUD") public class CustomerCrudSeparatedJavaTest { private static final HttpRequestBody customerPayload = http.json( "firstName", "FN", "lastName", "LN"); private static final HttpRequestBody changedCustomerPayload = http.json( "firstName", "FN", "lastName", "NLN"); private static int id; @BeforeAll @DisplayName("create customer") // optional friendly name for reporting purposes public static void createCustomer() { id = http.post("/customers", customerPayload, ((header, body) -> { return body.get("id"); })); actual(id).shouldNot(equal(0)); } @Test @Order(1) @DisplayName("read customer") public void read() { http.get("/customers/" + id, ((header, body) -> { body.should(equal(customerPayload)); })); } @Test @Order(2) // order dependence saves from creating customer on every test @DisplayName("update customer") public void update() { http.put("/customers/" + id, changedCustomerPayload, ((header, body) -> { body.should(equal(changedCustomerPayload)); })); http.get("/customers/" + id, ((header, body) -> { body.should(equal(changedCustomerPayload)); })); } @Test @Order(3) // but you can still run each method independently @DisplayName("delete customer") public void delete() { http.delete("/customers/" + id, ((header, body) -> { header.statusCode.should(equal(204)); })); http.get("/customers/" + id, ((header, body) -> { header.statusCode.should(equal(404)); })); id = -1; // marking as deleted to let cleanup step know that no delete is required } @AfterAll public static void cleanup() { // optional (since we create new ids all the time) step to keep your environment clean if (id == -1) { return; } http.delete("/customers/" + id); } }

Separate Methods Report

Now report has separate entries for each CRUD operation. Makes it possible to filter tests by create , update , read , delete to streamline investigation.