Creating complex domain objects

Building more complex objects may come in handy when testing business systems. This can be done using jqwik’s Combinators feature, which we’ll use in the following listing. Imagine that we have the following Book class, and we need to generate different books for a property-based test.

Listing 5.21 A simple Book class

public class Book {
 
  private final String title;
  private final String author;
  private final int qtyOfPages;
 
  public Book(String title, String author, int qtyOfPages) {
    this.title = title;
    this.author = author;
    this.qtyOfPages = qtyOfPages;
  }
 
  // getters...
}

One way to do this would be to have a property test that receives three parameters: a String for title, a String for author, and an Integer for quantity of pages. Inside the property test, we would instantiate the Book class. Jqwik offers a better way to do that, as shown in the next listing.

Listing 5.22 Using the Combinators API to generate complex objects

public class BookTest {
 
  @Property
  void differentBooks(@ForAll("books") Book book) {
    // different books!
    System.out.println(book);
 
    // write your test here!
  }
 
  @Provide
  Arbitrary<Book> books() {
    Arbitrary<String> titles = Arbitraries.strings().withCharRange(
      ➥ 'a', 'z')
        .ofMinLength(10).ofMaxLength(100);                              ❶
    Arbitrary<String> authors = Arbitraries.strings().withCharRange(
      ➥ 'a', 'z')
        .ofMinLength(5).ofMaxLength(21);                                ❶
    Arbitrary<Integer> qtyOfPages = Arbitraries.integers().between(
      ➥ 0, 450);                                                       ❶
 
 
    return Combinators.combine(titles, authors, qtyOfPages)
        .as((title, author, pages) -> new Book(title, author, pages));  ❷
  }
}

❶ Instantiates one arbitrary for each of the Book’s fields

❷ Combines them to generate an instance of Book

The Combinators API lets us combine different generators to build a more complex object. All we have to do is to build specific Arbitrarys for each of the attributes of the complex class we want to build: in this case, one Arbitrary<String> for the title, another Arbitrary<String> for the author, and one Arbitrary<Integer> for the number of pages. After that, we use the Combinators.combine() method, which receives a series of Arbitrarys and returns an Arbitrary of the complex object. The magic happens in the as() method, which gives us the values we use to instantiate the object.

Note how flexible jqwik is. You can build virtually any object you want. Moreover, nothing prevents you from building even more realistic input values: for example, instead of building random author names, we could develop something that returns real people’s names. Try implementing such an arbitrary yourself.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *