This post is about reducing manual data setup in unit tests. Typically such setup involves instantiating some classes and calling a bunch of setters. For example, in the the following test this is done in the createBookDTO()
method:
Note: links to source code provided at the end.
// Class under test
private final BookMapper bookMapper = new BookMapper();
@Test
void map() {
// Given
BookDTO bookDto = createBookDTO();
// When
Book book = bookMapper.toEntity(bookDto);
// Then
assertThat(book.getTitle()).isEqualTo(bookDto.getBookTitle());
// ... snip ... remaining assertions
}
// Data setup
private BookDTO createBookDTO() {
AuthorDTO authorDto = new AuthorDTO();
authorDto.setAuthorId(UUID.randomUUID().toString());
authorDto.setFirstName("Jane");
authorDto.setLastName("Doe");
BookDTO bookDto = new BookDTO();
bookDto.setBookId(UUID.randomUUID().toString());
bookDto.setIsbn("test-isbn");
bookDto.setBookTitle("test-title");
bookDto.setAuthor(authorDto);
bookDto.setGenre(Genre.FICTION);
bookDto.setPublishedOn(LocalDate.of(1865, 3, 17));
bookDto.setNumberOfPages(123);
bookDto.setPriceCents(3099);
return bookDto;
}
The setup done in createBookDTO()
is very typical for unit tests. However, it can be quite tedious, especially when dealing with large classes. What's more is that often the values themselves don't actually matter. Whether you set the name to "Jane Doe"
or "Foo Bar"
makes no difference. The end result is the same.
If values don't matter, then why not use a library to create and populate an object with random data? This is exactly what Instancio does. It is a library that generates objects for unit tests. Using Instancio, we can create a BookDTO
instance as follows:
private BookDTO createBookDTO() {
return Instancio.create(BookDTO.class);
}
This seems like a step in the right direction, but what if we need to customise some values of BookDTO
? Let's say the BookMapper
class that we are testing converts string UUID values to UUID
type:
UUID.fromString(bookId) // need a valid UUID string!
In this case, the test will fail unless our test objects contain valid ids (notice that setAuthorId()
and setBookId()
in the original createBookDTO()
method are both set to UUID.randomUUID().toString()
). To achieve this, we can use Instancio's builder API to set custom values:
Instancio.of(BookDTO.class)
.set(field(BookDTO.class, "bookId"), UUID.randomUUID().toString())
.set(field(AuthorDTO.class, "authorId"), UUID.randomUUID().toString())
.create();
For this simple test the above change is sufficient and now our test will pass. However, Instancio supports a number of other features for customising generated objects, for example:
Instancio.of(BookDTO.class)
.generate(field("genre"), gen -> gen.oneOf(Genre.CRIME, Genre.SCIFI, Genre.FANTASY))
.generate(field("isbn"), gen -> gen.text().pattern("#d-#d#d#d#d#d-#d#d#d-#d"))
.generate(field("numberOfPages"), gen -> gen.ints().range(100, 999))
.create();
There might be a follow up article to go into more detail. Please leave a comment if you'd like to see more examples, or if you have any questions. All feedback is welcome!
If you are interested in learning more, please see the user guide which also has a number of examples.
You can find the book-mapper-sample
project at https://github.com/instancio/instancio-samples
Top comments (1)
Work with lio app your team in real time by easily creating documents together and sharing the same with other users on Whatsapp, Gmail and other social apps.
Some comments have been hidden by the post's author - find out more