Skip to content
This repository has been archived by the owner on Feb 21, 2023. It is now read-only.

First8/junit-quickcheck-demo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build Status

Read the full article: https://technology.first8.nl/generating-test-data-with-junit-quickcheck/

Generative testing demo

This project contains examples to generate data for tests, using junit-quickcheck. The application itself is a rest service, with one end point serving 3 books.

All test classes need to have a @RunWith(JUnitQuickcheck.class) annotation.

Build-in datatypes

From BookResourceTest

    /**
     * Example using build types, which junit-quickcheck can generate.
     * 
     * @param title generated by junit-quickcheck
     * @param author generated by junit-quickcheck
     * @param publisher generated by junit-quickcheck
     * @param publishedOn generated by junit-quickcheck
     */
    @Property
    public void testConversions(//
            final String title, //
            final String author, //
            final String publisher, //
            final LocalDate publishedOn) {

        // Given a book
        final Book book = new Book(title, new Author(author),
                new Publisher(publisher), publishedOn);

        // When we create a resource based on that book
        final BookResource resource = BookResource.fromBook(book);
        // And convert the resource back to a book
        final Book converted = resource.toBook();

        // Then we expected the result to have the same property values as the
        // original book
        assertThat(converted, SamePropertyValuesAs.samePropertyValuesAs(book));
    }

Here title, author, publisher and publishedOn values are generated by junit-quickcheck. This test is run 100 times with random values.

User defined datatypes

    /**
     * Example using a user defined type, of which all constructor arguments are
     * build-in types.
     * 
     * @param resource generated by junit-quickcheck
     */
    @Property
    public void testConversions(// Given a resource
            final @From(Ctor.class) BookResource resource) {

        // When we convert the resource into a book
        final Book book = resource.toBook();
        // And we convert the book back to a resource
        final BookResource converted = BookResource.fromBook(book);

        // Then we expect the result to have the same property values as
        // the original resource
        assertThat(converted,
                SamePropertyValuesAs.samePropertyValuesAs(resource));
    }

Here we let junit-quickcheck generate BookResource objects. With @From(Ctor.class) we specify that junit-quickcheck should use the constructor. This means that we can only use constructors with only build-in datatypes as parameters.

Custom generator

    /**
     * Because book has a constructor with user defined data types (Author and
     * Publisher), the Ctor.class generator will not work.
     * 
     * Therefore, we need to create a generator, to generate a book.
     */
    public static final class BookGenerator extends Generator<Book> {
        /**
         * Generator to generate strings for title, author name and publisher
         * name.
         */
        private final StringGenerator stringGenerator = new StringGenerator();
        /**
         * Generator to generate dates.
         */
        private final LocalDateGenerator localDateGenerator =
                new LocalDateGenerator();

        public BookGenerator() {
            super(Book.class);
        }

        @Override
        public Book generate(final SourceOfRandomness random,
                final GenerationStatus status) {
            final String title = stringGenerator.generate(random, status);
            final String author = stringGenerator.generate(random, status);
            final String publisher = stringGenerator.generate(random, status);
            final LocalDate publishedOn =
                    localDateGenerator.generate(random, status);
            final Book book = new Book(title, new Author(author),
                    new Publisher(publisher), publishedOn);
            return book;
        }
    }

    /**
     * Example using the BookGenerator defined above, to generate books
     * 
     * @param book generated by junit-quickcheck
     */
    @Property
    public void testConversions(// Given a book
            final @From(BookGenerator.class) Book book) {

        // When we convert the book to a resource
        final BookResource resource = BookResource.fromBook(book);
        // and we convert the resource back to a book
        final Book converted = resource.toBook();

        // Then we expect the result to have the same property values as the
        // original book
        assertThat(converted, SamePropertyValuesAs.samePropertyValuesAs(book));
    }

In order to generate values of user defined types, with constructor parameters featuring even more user defined types, we must create our own Generator. We reference this generator in @From annotation.

Mocking and collections

From BookControllerTest

    @Mock
    private BookService bookService;

    @InjectMocks
    private BookController bookController;

    @Rule
    public MockitoRule mockitoRule = MockitoJUnit.rule();

Above, we set up mocking as usual.

    /**
     * Tests the book controller against a mock book service, using
     * junit-quickcheck to generate test data.
     * 
     * @param resources generated by junit-quickcheck
     */
    @Property()
    public void testBasedOnResources(//
            final List<@From(Ctor.class) BookResource> resources) {

        // Given an mocked bookservice, which returns generated data when
        // findAll() is called.
        when(bookService.findAll()).thenReturn(resources.stream()
                .map(BookResource::toBook).collect(Collectors.toList()));

        // When we call books() on the book controller
        final List<BookResource> results = bookController.books();

        // We expect the book controller to return book resources which match
        // the books
        Streams //
                .zip(resources.stream(), results.stream(), Pair::of)//
                .forEach(pair -> {
                    final BookResource reference = pair.getLeft();
                    final BookResource result = pair.getRight();
                    assertThat( //
                            reference, //
                            SamePropertyValuesAs.samePropertyValuesAs(result));
                });
    }

Here we let junit-quickcheck generate lists of BookResource objects. Note the @From(Ctor.class) annotation binds to the BookResource, the type parameter of List and not List itself.

About

Property based testing with junit-quickcheck

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages