Quantcast
Channel: Baeldung
Viewing all articles
Browse latest Browse all 4535

Custom Assertions with AssertJ

$
0
0

1. Overview

In this tutorial, we’ll walk through creating custom AssertJ assertions; the AssertJ’s basics can be found here.

Simply put, custom assertions allow creating assertions specific to our own classes, allowing our tests to better reflect the domain model.

2. Class Under Test

Test cases in this tutorial will be built around the Person class:

public class Person {
    private String fullName;
    private int age;
    private List<String> nicknames;

    public Person(String fullName, int age) {
        this.fullName = fullName;
        this.age = age;
        this.nicknames = new ArrayList<>();
    }

    public void addNickname(String nickname) {
        nicknames.add(nickname);
    }

    // getters
}

3. Custom Assertion Class

Writing a custom AssertJ assertion class is pretty simple. All we need to do is to declare a class that extends AbstractAssert, add a required constructor, and provide custom assertion methods.

The assertion class must extend the AbstractAssert class to give us access to essential assertion methods of the API, such as isNotNull and isEqualTo.

Here’s the skeleton of a custom assertion class for Person:

public class PersonAssert extends AbstractAssert<PersonAssert, Person> {

    public PersonAssert(Person actual) {
        super(actual, PersonAssert.class);
    }

    // assertion methods described later
}

We must specify two type arguments when extending the AbstractAssert class: the first is the custom assertion class itself, which is required for method chaining, and the second is the class under test.

To provide an entry point to our assertion class, we can define a static method that can be used to start an assertion chain:

public static PersonAssert assertThat(Person actual) {
    return new PersonAssert(actual);
}

Next, we’ll go over several custom assertions included in the PersonAssert class.

The first method verifies that the full name of a Person matches a String argument:

public PersonAssert hasFullName(String fullName) {
    isNotNull();
    if (!actual.getFullName().equals(fullName)) {
        failWithMessage("Expected person to have full name %s but was %s", 
          fullName, actual.getFullName());
    }
    return this;
}

The following method tests if a Person is an adult based on its age:

public PersonAssert isAdult() {
    isNotNull();
    if (actual.getAge() < 18) {
        failWithMessage("Expected person to be adult");
    }
    return this;
}

The last checks for the existence of a nickname:

public PersonAssert hasNickName(String nickName) {
    isNotNull();
    if (!actual.getNickNames().contains(nickName)) {
        failWithMessage("Expected person to have nickname %s", 
          nickName);
    }
    return this;
}

When having more than one custom assertion class, we may wrap all assertThat methods in a class, providing a static factory method for each of the assertion classes:

public class Assertions {
    public static PersonAssert assertThat(Person actual) {
        return new PersonAssert(actual);
    }

    // static factory methods of other assertion classes
}

The Assertions class shown above is a convenient entry point to all custom assertion classes.

Static methods of this class have the same name and are differentiated from each other by their parameter type.

4. In Action

The following test cases will illustrate the custom assertion methods we created in the previous section. Notice that the assertThat method is imported from our custom Assertions class, not the core AssertJ API.

Here’s how the hasFullName method can be used:

@Test
public void whenPersonNameMatches_thenCorrect() {
    Person person = new Person("John Doe", 20);
    assertThat(person)
      .hasFullName("John Doe");
}

This is a negative test case illustrating the isAdult method:

@Test
public void whenPersonAgeLessThanEighteen_thenNotAdult() {
    Person person = new Person("Jane Roe", 16);

    // assertion fails
    assertThat(person).isAdult();
}

and another test demonstrating the hasNickname method:

@Test
public void whenPersonDoesNotHaveAMatchingNickname_thenIncorrect() {
    Person person = new Person("John Doe", 20);
    person.addNickname("Nick");

    // assertion will fail
    assertThat(person)
      .hasNickname("John");
}

5. Assertions Generator

Writing custom assertion classes corresponding to the object model paves the way for very readable test cases.

However, if we have a lot of classes, it would be painful to manually create custom assertion classes for all of them. This is where the AssertJ assertions generator comes into play.

To use the assertions generator with Maven, we need to add a plugin to the pom.xml file:

<plugin>
    <groupId>org.assertj</groupId>
    <artifactId>assertj-assertions-generator-maven-plugin</artifactId>
    <version>2.1.0</version>
    <configuration>
        <classes>
            <param>com.baeldung.testing.assertj.custom.Person</param>
        </classes>
    </configuration>
</plugin>

The latest version of the assertj-assertions-generator-maven-plugin can be found here.

The classes element in the above plugin marks classes for which we want to generate assertions. Please see this post for other configurations of the plugin.

The AssertJ assertions generator creates assertions for each public property of the target class. The specific name of each assertion method depends on the field’s or property’s type. For a complete description of the assertions generator, check out this reference.

Execute the following Maven command in the project base directory:

mvn assertj:generate-assertions

We should see assertion classes generated in the folder target/generated-test-sources/assertj-assertions. For example, the generated entry point class for the generated assertions looks like this:

// generated comments are stripped off for brevity

package com.baeldung.testing.assertj.custom;

@javax.annotation.Generated(value="assertj-assertions-generator")
public class Assertions {

    @org.assertj.core.util.CheckReturnValue
    public static com.baeldung.testing.assertj.custom.PersonAssert
      assertThat(com.baeldung.testing.assertj.custom.Person actual) {
        return new com.baeldung.testing.assertj.custom.PersonAssert(actual);
    }

    protected Assertions() {
        // empty
    }
}

Now, we can copy the generated source files to the test directory, then add custom assertion methods to satisfy our testing requirements.

One important thing to notice is that the generated code isn’t guaranteed to be entirely correct. At this point, the generator isn’t a finished product, and the community is working on it.

Hence, we should use the generator as a supporting tool to make our life easier instead of taking it for granted.

6. Conclusion

In this tutorial, we’ve shown how to create custom assertions for creating readable test code with the AssertJ library, both manually and automatically.

If we have just a small number of classes under test, the manual solution is enough; otherwise, the generator should be used.

And, as always, the implementation of all the examples and code snippets can be found over on GitHub.


Viewing all articles
Browse latest Browse all 4535

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>