In this recipe, we will add AssertJ to your classpath (or check if it's already there) and take a look at a test that should show the concept that lies behind the AssertJ
library.
First, let's check the differences between the different AssertJ JAR files:
assertj-core
: This file contains the vast majority of assertions (there is rarely a need to have any additional dependencies)assertj-guava
: This file contains additional assertions for some of the Guava
library related classesassertj-neo4j
: This file contains additional assertions for the Neo4j graph database related classesassertj-joda-time
: This file contains additional assertions for the JodaTime
library related classesassertj-assertions-generator-maven-plugin
: This is a Maven plugin for generating AssertJ assertionsIn most cases, all you need is assertj-core
since it already has plenty of useful assertions.
Regardless of the fact that you are using JUnit or TestNG, you still have to add assertj-core
to your classpath since it isn't embedded into either of them.
The following is the dependency for AssertJ core (Maven):
<dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> <version>1.6.0</version> <scope>test</scope> </dependency>
The following is the dependency for AssertJ core (Gradle):
testCompile('org.assertj:assertj-core:1.6.0')
If you are not using any of the dependency managers, you have to download one of the aforementioned JAR files and add them to your classpath.
For this recipe, our system under test will be a NewPersonGenerator
class that will call an external service, NewIdentityCreator
, to generate a new identity for the current person, as shown in the following code:
public class NewPersonGenerator { private final NewIdentityCreator newIdentityCreator; public NewPersonGenerator(NewIdentityCreator newIdentityCreator) { this.newIdentityCreator = newIdentityCreator; } public Person generateNewIdentity(Person person) { String newName = newIdentityCreator.createNewName(person); int newAge = newIdentityCreator.createNewAge(person); List<Person> newSiblings = newIdentityCreator.createNewSiblings(person); return new Person(newName, newAge, newSiblings); } }
In order to use the AssertJ assertions in your tests, you have to perform the following steps:
Assertions.assertThat(T object).someAssertionMethod(...)
to perform assertion.The following snippet depicts the aforementioned scenario for JUnit (refer to Chapter 1, Getting Started with Mockito for information on the TestNG configuration):
@RunWith(MockitoJUnitRunner.class) public class NewPersonGeneratorTest { @Mock NewIdentityCreator newIdentityCreator; @InjectMocks NewPersonGenerator systemUnderTest; @Test public void should_return_person_with_new_identity() { // given Person person = new Person("Robert", 25, asList(new Person("John", 10), new Person("Maria", 12))); given(newIdentityCreator.createNewName(person)).willReturn("Andrew"); given(newIdentityCreator.createNewAge(person)).willReturn(45); given(newIdentityCreator.createNewSiblings(person)).willReturn(asList(new Person("Amy", 20), new Person("Alex", 25))); // when Person newPerson = systemUnderTest.generateNewIdentity(person); // then assertThat(newPerson).isNotNull().isNotEqualTo(person); assertThat(newPerson.getName()).isNotNull().startsWith("And").endsWith("rew"); assertThat(newPerson.getSiblings()).contains(new Person("Amy", 20), new Person("Alex", 25)); assertThat(newPerson.getAge()).isGreaterThan(25); assertThat(newPerson.getSiblings()).extracting("name", "age").contains(tuple("Amy", 20), tuple("Alex", 25)); } }
When you call Assertions.assertThat(T object)
, you can benefit from AssertJ's overloaded assertThat(…)
methods that can be used with different types of classes. The examples of such classes are given as follows:
public static BigDecimalAssert assertThat(BigDecimal actual);
public static BooleanAssert assertThat(boolean actual);
public static FileAssert assertThat(File actual);
public static <T> ObjectAssert<T> assertThat(T actual);
Each of the overloaded assertThat(…)
methods delegates to the instantiation of the proper implementation of the AbstractAssert
class that contains all of the basic assertions that come from implementing the Assert
interface. You also have access to the actual field called actual
that contains the object you are performing assertion against (which allows you to create your custom assertions quickly).
Due to the fact that AssertJ operates on overloaded methods that are always type-specific, your IDE will instantly help you find all of the matching assertion methods. For example, in the previous code snippet, we presented assertions for Files as assertThat(File actual). The execution of this method will return FileAssert that is file-specific and allows you to use such methods as follows (to mention only a few):
exists(), isDirectory(), isRelative(), hasParent(...),hasExtension(...)
Since AssertJ's main concept is to operate on fluent interfaces, and each assertion returns the assertion implementation itself, you do not have to combine several assertions into a single one as done in Hamcrest. Instead, you can just execute a chain of methods as follows:
assertThat(newPerson).isNotNull().isNotEqualTo(person);
AssertJ also proves to be extremely powerful in terms of performing assertions over iterables as follows:
assertThat(newPerson.getSiblings()).extracting("name", "age").contains(tuple("Amy", 20), tuple("Alex", 25));
You can easily extract (using the extracting method) certain properties of each of the iterables and check their state in comparison to specially created objects called tuples (check AssertJ examples of asserting iterables at https://github.com/joel-costigliola/assertj-examples/blob/master/assertions-examples/src/test/java/org/assertj/examples/IterableAssertionsExamples.java).
Tuples allow you to create a structure matching your extracted elements. In other words, for the aforementioned siblings that are of a Person
type, we extract two strings from the properties name
and age
Next, we compare them against a structure having name equal to Amy
and age equal to 20
and then against name equal to Alex
and age equal to 25
. Of course, this is only a small portion of AssertJ possibilities, but it should give you a clue of how powerful and readable AssertJ is.
From AssertJ version 1.6.0, you can make your tests look even more readable and follow the BDD naming by changing the assertThat(...)
method into the then(...)
method. You can rewrite the test to follow that approach, as shown in the following code:
@Test public void should_return_person_with_new_identity() { // given Person person = new Person("Robert", ROBERT_AGE,newArrayList(new Person("John", 10), new Person("Maria", 12))); given(newIdentityCreator.createNewName(person)).willReturn("Andrew"); given(newIdentityCreator.createNewAge(person)).willReturn(45); given(newIdentityCreator.createNewSiblings(person)).willReturn(newArrayList(new Person("Amy", 20),new Person("Alex", 25))); // when Person newPerson = systemUnderTest.generateNewIdentity(person); // then then(newPerson).isNotNull().isNotEqualTo(person); then(newPerson.getName()).isNotNull().startsWith("And").endsWith("rew"); then(newPerson.getSiblings()).contains(new Person("Amy", 20), new Person("Alex", 25)); then(newPerson.getAge()).isGreaterThan(25); then(newPerson.getSiblings()).extracting("name", "age").contains(tuple("Amy", 20), tuple("Alex", 25)); }
3.148.107.254