AssertJ - fluent assertions java library (original) (raw)

The goal of this document is to provide comprehensive reference documentation for programmers writing tests assertions with AssertJ.

2.1. What is AssertJ Core?

AssertJ is a Java library that provides a rich set of assertions and truly helpful error messages, improves test code readability, and is designed to be super easy to use within your favorite IDE.

http://www.javadoc.io/doc/org.assertj/assertj-core/ is the latest version of AssertJ Core Javadoc, each assertion is explained, most of them with code examples so be sure to check it if you want to know what a specific assertion does.

Here are a few examples of AssertJ assertions:

// entry point for all assertThat methods and utility methods (e.g. entry)
import static org.assertj.core.api.Assertions.*;

// basic assertions
assertThat(frodo.getName()).isEqualTo("Frodo");
assertThat(frodo).isNotEqualTo(sauron);

// chaining string specific assertions
assertThat(frodo.getName()).startsWith("Fro")
                           .endsWith("do")
                           .isEqualToIgnoringCase("frodo");

// collection specific assertions (there are plenty more)
// in the examples below fellowshipOfTheRing is a List<TolkienCharacter>
assertThat(fellowshipOfTheRing).hasSize(9)
                               .contains(frodo, sam)
                               .doesNotContain(sauron);

// as() is used to describe the test and will be shown before the error message
assertThat(frodo.getAge()).as("check %s's age", frodo.getName()).isEqualTo(33);

// exception assertion, standard style ...
assertThatThrownBy(() -> { throw new Exception("boom!"); }).hasMessage("boom!");
// ... or BDD style
Throwable thrown = catchThrowable(() -> { throw new Exception("boom!"); });
assertThat(thrown).hasMessageContaining("boom");

// using the 'extracting' feature to check fellowshipOfTheRing character's names
assertThat(fellowshipOfTheRing).extracting(TolkienCharacter::getName)
                               .doesNotContain("Sauron", "Elrond");

// extracting multiple values at once grouped in tuples
assertThat(fellowshipOfTheRing).extracting("name", "age", "race.name")
                               .contains(tuple("Boromir", 37, "Man"),
                                         tuple("Sam", 38, "Hobbit"),
                                         tuple("Legolas", 1000, "Elf"));

// filtering a collection before asserting
assertThat(fellowshipOfTheRing).filteredOn(character -> character.getName().contains("o"))
                               .containsOnly(aragorn, frodo, legolas, boromir);

// combining filtering and extraction (yes we can)
assertThat(fellowshipOfTheRing).filteredOn(character -> character.getName().contains("o"))
                               .containsOnly(aragorn, frodo, legolas, boromir)
                               .extracting(character -> character.getRace().getName())
                               .contains("Hobbit", "Elf", "Man");

// and many more assertions: iterable, stream, array, map, dates, path, file, numbers, predicate, optional ...

2.2. Getting Help

2.3. Contributing to this guide

You are very welcome to suggest or contribute improvements to this guide, that’s one great way to give back to open source projects!

This guide is written with the awesome Asciidoctor which makes it easy to improve.

2.4. Quick start

This guide is for the AssertJ Core module.

2.4.1. Supported Java Versions

AssertJ Core requires Java 8 or higher.

Android Support

AssertJ Core does not officially support Android but is compatible with Android API Level 26+, except for soft assertions and assumptions.

2.4.2. Get AssertJ Core

The AssertJ Core artifact can be included directly using its dependency metadata or indirectly via the Bill of Materials POM.

Maven
<dependency>
  <groupId>org.assertj</groupId>
  <artifactId>assertj-core</artifactId>
  <version>3.27.2</version>
  <scope>test</scope>
</dependency>
Gradle
testImplementation("org.assertj:assertj-core:3.27.2")
Other build tools
Spring Boot

Spring Boot provides automatic support for managing the version of AssertJ used in your project. In addition, the spring-boot-starter-test artifact automatically includes testing libraries such as JUnit Jupiter, AssertJ Core, Mockito, etc.

If you need to override the version of a dependency used in your Spring Boot application, you have to override the exact name of the version property defined in the BOM used by the Spring Boot plugin. For example, the name of the AssertJ version property in Spring Boot is assertj.version. The mechanism for changing a dependency version is documented for both Maven and Gradle.

With Maven, you can override the AssertJ version by including the following in your pom.xml file.

<properties>
  <assertj.version>3.27.2</assertj.version>
</properties>

With Gradle, you can override the AssertJ version by including the following in your build.gradle file.

ext['assertj.version'] = '3.27.2'

2.4.3. Use Assertions class entry point

The Assertions class is the only class you need to start using AssertJ, it provides all the methods you need.

Alternatively your test class can implement WithAssertions to access the same methods.

One Assertions static import to rule them all …​

import static org.assertj.core.api.Assertions.*;

... or many if you prefer:

import static org.assertj.core.api.Assertions.assertThat;  // main one
import static org.assertj.core.api.Assertions.atIndex; // for List assertions
import static org.assertj.core.api.Assertions.entry;  // for Map assertions
import static org.assertj.core.api.Assertions.tuple; // when extracting several properties at once
import static org.assertj.core.api.Assertions.fail; // use when writing exception tests
import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; // idem
import static org.assertj.core.api.Assertions.filter; // for Iterable/Array assertions
import static org.assertj.core.api.Assertions.offset; // for floating number assertions
import static org.assertj.core.api.Assertions.anyOf; // use with Condition
import static org.assertj.core.api.Assertions.contentOf; // use with File assertions
Alternative entry points

AssertJ provides other entry points class, notably the WithAssertions interface and BDDAssertions for BDD style assertions that replace assertThat by then.

WithAssertions example:

import org.assertj.core.api.WithAssertions;

public class WithAssertionsExamples extends AbstractAssertionsExamples implements WithAssertions {

  // the data used are initialized in AbstractAssertionsExamples.

  @Test
  public void withAssertions_examples() {

    // assertThat methods come from WithAssertions - no static import needed
    assertThat(frodo.age).isEqualTo(33);
    assertThat(frodo.getName()).isEqualTo("Frodo").isNotEqualTo("Frodon");

    assertThat(frodo).isIn(fellowshipOfTheRing);
    assertThat(frodo).isIn(sam, frodo, pippin);
    assertThat(sauron).isNotIn(fellowshipOfTheRing);

    assertThat(frodo).matches(p -> p.age > 30 && p.getRace() == HOBBIT);
    assertThat(frodo.age).matches(p -> p > 30);
  }
}

BDDAssertions example:

import static org.assertj.core.api.BDDAssertions.then;

public class BDDAssertionsExamples extends AbstractAssertionsExamples {

  // the data used are initialized in AbstractAssertionsExamples.

  @Test
  public void withAssertions_examples() {

    // then methods come from BDDAssertions.then static
    then(frodo.age).isEqualTo(33);
    then(frodo.getName()).isEqualTo("Frodo").isNotEqualTo("Frodon");

    then(frodo).isIn(fellowshipOfTheRing);
    then(frodo).isIn(sam, frodo, pippin);
    then(sauron).isNotIn(fellowshipOfTheRing);

    then(frodo).matches(p -> p.age > 30 && p.getRace() == HOBBIT);
    then(frodo.age).matches(p -> p > 30);
  }
}
IDE configuration

You can configure your IDE so that when you start typing as and trigger code completion assertThat will show up in the suggested completions.

Eclipse:

  1. Go to Window > Preferences > Java > Editor > Content Assist > Favorites > New Type.
  2. Enter org.assertj.core.api.Assertions and click OK.
  3. Check that you see org.assertj.core.api.Assertions.* in Favorites.

Intellij Idea: No special configuration is needed, just start typing asser and then invoke completion (Ctrl-Space) twice.

2.4.4. Use code completion

Type assertThat followed by the object under test and a dot …​ and any Java IDE code completion will show you all available assertions.

assertThat(objectUnderTest). (1)
1 Use IDE code completion after the dot.

Example for String assertions:

ide completion

2.5. Core assertions guide

This section describes the assertions provided by AssertJ Core and other useful features to get the best of it.

AssertJ Core Javadoc explains each assertion, most of them with code examples so be sure to check it if you want to know what a specific assertion does.

2.5.1. A simple example

Let’s start with a simple example showing a few important things.

import static org.assertj.core.api.Assertions.assertThat; (1)

import org.junit.jupiter.api.Test;

public class SimpleAssertionsExample {

  @Test
  void a_few_simple_assertions() {
    assertThat("The Lord of the Rings").isNotNull()  (2) (3)
                                       .startsWith("The") (4)
                                       .contains("Lord") (4)
                                       .endsWith("Rings"); (4)
  }

}
1 Statically import org.assertj.core.api.Assertions.assertThat
2 Pass the object under test as the sole assertThat() parameter
3 Use code completion to discover and call assertions
4 Chain as many assertions as you need

Except for isNotNull which is a base assertion, the other assertions are String specific as our object under test is a String.

2.5.2. Supported type assertions

AssertJ provides assertions specific to the object under test type, the following sections list the supported types grouped by categories.

The provided assertions for each of these types are documented later on.

Common types
BigDecimal BigInteger
CharSequence Class
Date File
Future / CompletableFuture InputStream
Iterable (including any kind of Collection) Iterator
List Map
Object Object[] and Object[][]
Optional OptionalInt / OptionalLong / OptionalDouble Path
Predicate Stream
String Throwable / Exception
Primitive types
Primitive types and their wrapper: short / Short int / Integer long / Long byte / Byte char / Character float / Float double / Double Primitive type arrays: short[] int[] long[] byte[] char[] float[] double[] Primitive type 2D arrays: short[][] int[][] long[][] byte[][] char[][] float[][] double[][]
Java 8 Temporal types
Instant LocalDate
LocalDateTime LocalTime
OffsetDateTime OffsetTime
ZonedDateTime Period
Atomic types
Atomic basic types: AtomicInteger AtomicLong AtomicBoolean Atomic array types: AtomicIntegerArray AtomicLongArray
Atomic reference types: AtomicMarkableReference AtomicStampedReferenceAssert Atomic updater types: AtomicIntegerFieldUpdater AtomicLongFieldUpdater AtomicReferenceFieldUpdater
Adder types: LongAdder

2.5.3. Assertion description

It is often valuable to describe the assertion performed, especially for boolean assertions where the default error message just complains that it got false instead of true (or vice versa).

You can set such a description with as(String description, Object…​ args) but remember to do it before calling the assertion otherwise it is simply ignored as a failing assertion breaks the chained calls.

Example of a failing assertion with a description:

TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, Race.HOBBIT);

// failing assertion, remember to call as() before the assertion!
assertThat(frodo.getAge()).as("check %s's age", frodo.getName())
                          .isEqualTo(100);

The error message starts with the given description in [] :

[check Frodo's age] expected:<100> but was:<33>
Printing or consuming description

AssertJ can print each assertion description (when it is set), to do so call Assertions.setPrintAssertionsDescription(true);.

If printing assertion descriptions is not what you need, you can alternatively register a Consumer<Description> that will be called each time a description is set.

Both options are exposed in AssertJ Configuration class.

Example: using a description consumer

// initialize the description consumer
final StringBuilder descriptionReportBuilder = new StringBuilder(String.format("Assertions:%n"));
Consumer<Description> descriptionConsumer = desc -> descriptionReportBuilder.append(String.format("-- %s%n", desc));

// use the description consumer for any following assertions descriptions.
Assertions.setDescriptionConsumer(descriptionConsumer);

// execute some assertions
TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, Race.HOBBIT);
assertThat(frodo.getName()).as("check name")
                          .isEqualTo("Frodo");
assertThat(frodo.getAge()).as("check age")
                          .isEqualTo(33);

// get the report
String descriptionReport = descriptionReportBuilder.toString();

resulting descriptionReport:

Assertions:
-- check name
-- check age

2.5.4. Overriding error message

AssertJ tries its best to give helpful error messages, but you can always change it with overridingErrorMessage() or withFailMessage().

Example with this failing test:

TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, Race.HOBBIT);
TolkienCharacter sam = new TolkienCharacter("Sam", 38, Race.HOBBIT);
// failing assertion, remember to call withFailMessage/overridingErrorMessage before the assertion!
assertThat(frodo.getAge()).withFailMessage("should be %s", frodo)
                          .isEqualTo(sam);

The error message is:

java.lang.AssertionError: should be TolkienCharacter [name=Frodo, age=33, race=HOBBIT]
Lazy error message overriding

If the error message is expensive to build, use the overloaded methods taking a Supplier<String> instead of a String, the message will only be built if the assertion fails.

Example:

assertThat(player.isRookie()).overridingErrorMessage(() -> "Expecting Player to be a rookie but was not.")
                             .isTrue();

assertThat(player.isRookie()).withFailMessage(() -> "Expecting Player to be a rookie but was not.")
                             .isTrue();

2.5.5. Avoiding incorrect usage

There are a few things to keep in mind when using AssertJ to avoid misusing it.

Forgetting to call an assertion

The main trap is to pass the object under test to assertThat() and forget to call an assertion afterward. This misuse can be detected by multiple static code analysis tools:

Here’s what it looks like in SpotBugs:

SpotBugs detecting AssertJ invalid usage

Figure 1. SpotBugs detecting AssertJ invalid usage

The following examples show incorrect AssertJ API usage to avoid!

Bad

// DON'T DO THIS ! It does not assert anything
assertThat(actual.equals(expected));

Good

// DO THIS:
assertThat(actual).isEqualTo(expected);

// OR THIS (less classy but ok):
assertThat(actual.equals(expected)).isTrue();

Bad

// DON'T DO THIS ! It does not assert anything and passes
assertThat(1 == 2);

Good

// DO THIS: (fails as expected)
assertThat(1).isEqualTo(2);

// OR THIS (less classy but ok):
assertThat(1 == 2).isTrue();
Calling as() after the assertion

Describing an assertion must be done before calling the assertion. Otherwise it is ignored as a failing assertion will prevent the call to as().

Bad

// DON'T DO THIS ! as/describedAs have no effect after the assertion
assertThat(actual).isEqualTo(expected).as("description");
assertThat(actual).isEqualTo(expected).describedAs("description");

Good

// DO THIS: use as/describedAs before the assertion
assertThat(actual).as("description").isEqualTo(expected);
assertThat(actual).describedAs("description").isEqualTo(expected);
Calling withFailMessage/overridingErrorMessage after the assertion

Setting an error message must be done before calling the assertion. Otherwise it is ignored as a failing assertion will prevent the call to withFailMessage() / overridingErrorMessage().

Bad

// DON'T DO THIS ! overridingErrorMessage/withFailMessage have no effect after the assertion
assertThat(actual).isEqualTo(expected).overridingErrorMessage("custom error message");
assertThat(actual).isEqualTo(expected).withFailMessage("custom error message");

Good

// DO THIS: use overridingErrorMessage/withFailMessage before the assertion
assertThat(actual).overridingErrorMessage("custom error message").isEqualTo(expected);
assertThat(actual).withFailMessage("custom error message").isEqualTo(expected);
Setting a comparator after the assertion

Setting comparators must be done before calling the assertion. Otherwise it is ignored as a failing assertion will prevent the call to usingComparator() / usingElementComparator().

Bad

// DON'T DO THIS ! Comparator is not used
assertThat(actual).isEqualTo(expected).usingComparator(new CustomComparator());

Good

// DO THIS:
assertThat(actual).usingComparator(new CustomComparator()).isEqualTo("a");

2.5.6. Configuring AssertJ

This section describes the different ways to configure AssertJ, either by setting configuration properties individually or globally using the Configuration class.

To be effective the configuration changes must be applied before the tests are executed, depending on the scope of the tests this means different things:

Configuring single properties

The Assertions class provides static methods to change each configuration properties.

Assertions.setAllowComparingPrivateFields(true);
Assertions.setAllowExtractingPrivateFields(false);
Assertions.setExtractBareNamePropertyMethods(false);
Assertions.setLenientDateParsing(true);
Assertions.setMaxElementsForPrinting(100);
Assertions.setMaxLengthForSingleLineDescription(250);
Assertions.setRemoveAssertJRelatedElementsFromStackTrace(true);
Assertions.useRepresentation(myRepresentation);
Assertions.registerCustomDateFormat(myCustomDateFormat);
Assertions.setPrintAssertionsDescription(true);
Assertions.setConsumerDescription(description -> writeToFile(description, report));
Representation

This property allows you to register a Representation to control the way AssertJ formats the different types displayed in the assertion error messages. Consult the Controlling type formatting chapter for details.

Defaults to StandardRepresentation.

AllowComparingPrivateFields

Globally sets whether the use of private fields is allowed for field/property by field/property comparison. Defaults to true.

Globally sets whether the AssertJ extracting capability should be allowed to extract private fields. Defaults to true.

Globally sets whether the AssertJ extracting capability considers bare-named property methods like String name(). Defaults to true.

LenientDateParsing

Specify whether or not date/time parsing is to be lenient for AssertJ default date formats. With lenient parsing, the parser may use heuristics to interpret inputs that do not precisely match this object’s format. With strict parsing, inputs must match this object’s format.

Custom DateFormat

In addition to the default date formats, you can register some custom ones that AssertJ will use in date assertions (see also Assertions.registerCustomDateFormat).

Note that custom date formats take precedence over default ones.

MaxElementsForPrinting

In error messages, sets the threshold for how many elements from one iterable/array/map will be included in the description. Defaults to 1000.

The point of this property is to avoid printing iterable/array/map with too many elements in error messages.

MaxLengthForSingleLineDescription

In error messages, sets the threshold when iterable/array formatting will be on one line (if their String description is less than this parameter) or it will be formatted with one element per line. Defaults to 80.

Example:

String[] greatBooks = array("A Game of Thrones", "The Lord of the Rings", "Assassin's Apprentice");

this array is formatted on one line as its length < 80:

["A Game of Thrones", "The Lord of the Rings", "Assassin's Apprentice"]

Whereas this array …​

String[] greatBooks = array("A Game of Thrones", "The Lord of the Rings", "Assassin's Apprentice", "Guards! Guards! (Discworld)");

... is formatted on multiple lines with one element per line:

["A Game of Thrones",
 "The Lord of the Rings",
 "Assassin's Apprentice",
 "Guards! Guards! (Discworld)"]

Sets whether the elements related to AssertJ are removed from assertion errors stack trace. Defaults to true.

AssertJ Configuration

Since 3.13.0, AssertJ exposes a org.assertj.core.configuration.Configuration object providing access to all AssertJ globally configurable properties.

You can create an instance of org.assertj.core.configuration.Configuration and change indivual properties through setters or create your own custom configuration by inheriting from it and overriding the methods to change the default behavior as in the CustomConfiguration example below.

| | Your configuration will be effective once you call Configuration.apply() or Configuration.applyAndDisplay(). | | --------------------------------------------------------------------------------------------------------------- |

Example:

Configuration configuration = new Configuration();

configuration.setBareNamePropertyExtraction(false);
configuration.setComparingPrivateFields(false);
configuration.setExtractingPrivateFields(false);
configuration.setLenientDateParsing(true);
configuration.setMaxElementsForPrinting(1001);
configuration.setMaxLengthForSingleLineDescription(81);
configuration.setRemoveAssertJRelatedElementsFromStackTrace(false);

// don't forget to apply it!
configuration.applyAndDisplay();

Printing the above configuration produces the following output:

Applying configuration org.assertj.core.configuration.Configuration
- representation .................................. = BinaryRepresentation
- comparingPrivateFieldsEnabled ................... = false
- extractingPrivateFieldsEnabled .................. = true
- bareNamePropertyExtractionEnabled ............... = false
- lenientDateParsingEnabled ....................... = true
- additional date formats ......................... = [yyyy_MM_dd, yyyy|MM|dd]
- maxLengthForSingleLineDescription ............... = 150
- maxElementsForPrinting .......................... = 2000
- removeAssertJRelatedElementsFromStackTraceEnabled = true
Automagic configuration discovery

This section describes a way to register an AssertJ Configuration without using any test framework hooks like BeforeAllCallback.

Follow the steps below to register your Configuration as an SPI:

This is all you have to do, AssertJ will pick up the Configuration automatically and display it at the first interaction with AssertJ.

Here’s an example of a custom configuration class:

package example.core;

import static org.assertj.core.presentation.BinaryRepresentation.BINARY_REPRESENTATION;
import static org.assertj.core.util.Lists.list;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.List;

import org.assertj.core.configuration.Configuration;
import org.assertj.core.presentation.Representation;

class CustomConfiguration extends Configuration {

  private static final SimpleDateFormat DATE_FORMAT1 = new SimpleDateFormat("yyyy_MM_dd");
  private static final SimpleDateFormat DATE_FORMAT2 = new SimpleDateFormat("yyyy|MM|dd");

  // we keep the default behavior for extractingPrivateFieldsEnabled since it is not overridden

  @Override
  public Representation representation() {
    return BINARY_REPRESENTATION;
  }

  @Override
  public boolean bareNamePropertyExtractionEnabled() {
    return false;
  }

  @Override
  public boolean comparingPrivateFieldsEnabled() {
    return false;
  }

  @Override
  public boolean lenientDateParsingEnabled() {
    return true;
  }

  @Override
  public List<DateFormat> additionalDateFormats() {
    return list(DATE_FORMAT1, DATE_FORMAT2);
  }

  @Override
  public int maxElementsForPrinting() {
    return 2000;
  }

  @Override
  public int maxLengthForSingleLineDescription() {
    return 150;
  }
}

With this custom configuration, the content of META-INF/services/org.assertj.core.configuration.Configuration must be:

example.core.CustomConfiguration

Printing the CustomConfiguration shows:

Applying configuration example.core.CustomConfiguration
- representation .................................. = BinaryRepresentation
- comparingPrivateFieldsEnabled ................... = false
- extractingPrivateFieldsEnabled .................. = true
- bareNamePropertyExtractionEnabled ............... = false
- lenientDateParsingEnabled ....................... = true
- additionnal date formats ........................ = [yyyy_MM_dd, yyyy|MM|dd]
- maxLengthForSingleLineDescription ............... = 150
- maxElementsForPrinting .......................... = 2000
- removeAssertJRelatedElementsFromStackTraceEnabled = true

2.5.7. Controlling type formatting

Assertions error messages use a Representation to format the different types involved. There are multiple ways of registering a custom Representation for assertions:

Let’s go over these different options with a custom Representation.

Creating a custom Representation

An example of a custom Representation:

// dummy class
private class Example {}

public class CustomRepresentation extends StandardRepresentation { (1)

  // override fallbackToStringOf to handle Example formatting
  @Override
  public String fallbackToStringOf(Object o) { (2)
    if (o instanceof Example) return "Example";
    // fallback to default formatting.
    return super.fallbackToStringOf(o);
  }

  // override a predefined type formatting: String
  @Override
  protected String toStringOf(String str) { (3)
    return "$" + str + "$";
  }
}
1 Extends org.assertj.core.presentation.StandardRepresentation to get AssertJ default representation.
2 Override fallbackToStringOf and handle your specific types before falling back to the default formatting.
3 Change a predefined type formatting by overriding the toStringOf method that takes it as a parameter.

Let’s see the above custom representation in action when representing Example or String instances.

This assertion fails …​

assertThat(new Example()).isNull();

…​with the following error:

expected:<[null]> but was:<[Example]>

This one fails …​

// this one fails ...
assertThat("foo").startsWith("bar");

…​with the following error:

Expecting:
  <$foo$>
to start with:
  <$bar$>
Changing the default global scope custom representation

You only have to register CustomRepresentation once but need to do it before executing any tests, for the tests executed before that, AssertJ will use the default representation.

// to call before executing tests
Assertions.useRepresentation(new CustomRepresentation());

Consider writing a JUnit 5 extension implementing BeforeAllCallback to make sure the representation is set once for all before any test is executed.

Per assertion scope custom representation

Follow this approach if you want to use a specific representation for a single assertion only.

Example with the failing assertions used before:

Representation customRepresentation = new CustomRepresentation();

// this assertion fails ...
assertThat(new Example()).withRepresentation(customRepresentation)
                         .isNull();

assertThat("foo").withRepresentation(customRepresentation)
                 .startsWith("bar");
Registering multiple fine-grained representations

Since 3.22.0 AssertJ allows registering multiple representations (one per jar).

The typical use case is for different domain-specific libraries to be able to independently register Representation implementations for their specific domain objects.

| | In case different representations can represent the same type, the one with the highest priority wins. | | --------------------------------------------------------------------------------------------------------- |

Let’s take a concrete example where we have two domain specific libraries: Lotr and star wars and a project that uses them both.

The Lotr library is composed of an Hobbit class and a specific representation for it, note that LotrRepresentation represents Hobbits starting with HOBBIT unlike Hobbit toString method:

package org.assertj.example.lotr;

public class Hobbit {

  public String name;
  public String age;

  @Override
  public String toString() {
    return format("Hobbit [name=%s, age=%s]", name, age);
  }
}

public class LotrRepresentation implements Representation {

  @Override
  public String toStringOf(Object object) {
    if (object instanceof Hobbit) {
      Hobbit hobbit = (Hobbit) object;
      return String.format("HOBBIT [name=%s, age=%s]", hobbit.name, hobbit.age);
    }
    return null;
  }

  // only needed if another library was to represent Hobbit, in this case the one with highest priority wins
  @Override
  public int getPriority() {
    return 5;
  }
}

LotrRepresentation is registered by creating a META-INF/services/org.assertj.core.presentation.Representation file that contain org.assertj.example.lotr.LotrRepresentation, the file must be available in the classpath (typically by putting it in src/main/resources it will end up in the library jar).

Similarly the star wars library defines a Jedi and a StarWarsRepresentation:

package org.assertj.example.starwars;

public class Jedi {

  public String name;
  public String age;

  @Override
  public String toString() {
    return format("Jedi [name=%s, age=%s]", name, age);
  }
}

public class StarWarsRepresentation implements Representation {

  @Override
  public String toStringOf(Object object) {
    if (object instanceof Jedi) {
      Jedi jedi = (Jedi) object;
      return String.format("JEDI [name=%s, age=%s]", jedi.name, jedi.age);
    }
    return null;
  }

  @Override
  public int getPriority() {
    return 10;
  }
}

Same as the Lotr library, StarWarsRepresentation is registered by creating a META-INF/services/org.assertj.core.presentation.Representation file that contain org.assertj.example.starwars.StarWarsRepresentation.

The consuming project specifies both libraries as dependencies, since both have registered a representation, AssertJ will discover them and keep them in a composite representation that aggregates all registered representaions.

The following test fails with frodo and luke being represented by LotrRepresentation and StarWarsRepresentation respectively.

Hobbit frodo = new Hobbit();
frodo.name = "Frodo";
frodo.age = "33";

Jedi luke = new Jedi();
luke.name = "Luke";
luke.age = "23";

assertThat(frodo).isEqualTo(luke);

Error message:

org.opentest4j.AssertionFailedError:
expected: JEDI [name=Luke, age=23]
 but was: HOBBIT [name=Frodo, age=33]

2.5.8. Common assertions

This section describes the assertions common to all types, the Javadoc for common assertions methods is available here.

2.5.9. Object assertions

The Javadoc for Object assertions is available here.

2.5.10. String/CharSequence assertions

This section describes all the available assertions for CharSequence (including String, StringBuilder, StringBuffer, …​):

The Javadoc for CharSequence assertions is available here.

2.5.11. Iterable and array assertions

Checking iterables/arrays content

There are different flavors of contains assertion, here’s a table to help choose the most relevant one:

Assertion Description
contains Verifies that the actual iterable/array contains the given values in any order
containsOnly Verifies that the actual group contains only the given values and nothing else in any order and ignoring duplicates (i.e. once a value is found, its duplicates are also considered found)
containsExactly Verifies that the actual iterable/array contains exactly the given values and nothing else in order
containsExactlyInAnyOrder Verifies that the actual iterable/array contains exactly the given values and nothing else in any order
containsSequence Verifies that the actual group contains the given sequence in the correct order and without extra values between the sequence values
containsSubsequence Verifies that the actual group contains the given subsequence in the correct order possibly with other values between them
containsOnlyOnce Verifies that the actual iterable/array contains the given values only once
containsAnyOf Verifies that the actual iterable/array contains at least one of the given values (like an or operator on the given values)

| | the assertions above have a variant accepting an iterable/array argument, ex: containsExactly(E…​) and containsExactlyElementsOf(Iterable) | | --------------------------------------------------------------------------------------------------------------------------------------------- |

Verify assertions on some elements
Satisfy

You can assert that all or any elements verify the given assertions with allSatisfy and anySatisfy, conversely noneSatisfy lets you assert that no elements verify the given assertions.

The given assertions are expressed with a Consumer (typically with a lambda).

Examples:

List<TolkienCharacter> hobbits = list(frodo, sam, pippin);

// all elements must satisfy the given assertions
assertThat(hobbits).allSatisfy(character -> {
  assertThat(character.getRace()).isEqualTo(HOBBIT);
  assertThat(character.getName()).isNotEqualTo("Sauron");
});

// at least one element must satisfy the given assertions
assertThat(hobbits).anySatisfy(character -> {
  assertThat(character.getRace()).isEqualTo(HOBBIT);
  assertThat(character.getName()).isEqualTo("Sam");
});

// no element must satisfy the given assertions
assertThat(hobbits).noneSatisfy(character -> assertThat(character.getRace()).isEqualTo(ELF));

| | if allSatisfy fails, all the elements and their failing the assertions are reported. | | --------------------------------------------------------------------------------------- |

Match

You can assert that all or any elements match the given Predicate with allMatch and anyMatch, conversely noneMatch lets you assert that no elements verify the given predicate.

Examples:

List<TolkienCharacter> hobbits = list(frodo, sam, pippin);

assertThat(hobbits).allMatch(character -> character.getRace() == HOBBIT, "hobbits")
                   .anyMatch(character -> character.getName().contains("pp"))
                   .noneMatch(character -> character.getRace() == ORC);

| | You can pass a predicate description to make the error message more explicit if the assertion fails. | | ------------------------------------------------------------------------------------------------------- |

The idea is to navigate to a given element in order to check it, you can navigate to the first, last or any element by index or if you expect only one element use singleElement.

| | this is only available for iterables at the moment. | | ------------------------------------------------------ |

First / last / element(index)

Use first, last and element(index) to navigate to the corresponding element, after navigating you can only use object assertions unless you have specified an Assert class or preferrably an InstanceOfAssertFactory as shown in the following examples.

Examples:

// only object assertions available after navigation
Iterable<TolkienCharacter> hobbits = list(frodo, sam, pippin);
assertThat(hobbits).first().isEqualTo(frodo);
assertThat(hobbits).element(1).isEqualTo(sam);
assertThat(hobbits).last().isEqualTo(pippin);

// strongly typed String assertions after navigation
Iterable<String> hobbitsName = list("frodo", "sam", "pippin");
// STRING is an InstanceOfAssertFactory from org.assertj.core.api.InstanceOfAssertFactories.STRING
// as() is just synthetic sugar for readability
assertThat(hobbitsName).first(as(STRING))
                       .startsWith("fro")
                       .endsWith("do");
assertThat(hobbitsName).element(1, as(STRING))
                       .startsWith("sa")
                       .endsWith("am");
assertThat(hobbitsName).last(as(STRING))
                       .startsWith("pip")
                       .endsWith("pin");

// alternative for strongly typed assertions
assertThat(hobbitsName, StringAssert.class).first()
                                           .startsWith("fro")
                                           .endsWith("do");
Single element

singleElement checks that the iterable has only one element and navigates to it, after navigating you can only use object assertions unless you have specified an Assert class or preferrably an InstanceOfAssertFactory as shown in the following examples.

Examples:

Iterable<String> babySimpsons = list("Maggie");

// only object assertions available
assertThat(babySimpsons).singleElement()
                        .isEqualTo("Maggie");

// to get specific typed assertions, pass the corresponding InstanceOfAssertFactory from
// org.assertj.core.api.InstanceOfAssertFactories.STRING), as() is just synthetic sugar for readability
assertThat(babySimpsons).singleElement(as(STRING))
                        .endsWith("gie");

// alternative for strongly typed assertions
assertThat(babySimpsons, StringAssert.class).singleElement()
                                            .startsWith("Mag");
Filtering elements

Filtering is handy to target assertions on some specific elements, the filter criteria can be expressed by:

Filtering with a Predicate

You specify the filter condition using simple predicate, best expressed with a lambda.

Example:

assertThat(fellowshipOfTheRing).filteredOn( character -> character.getName().contains("o") )
                               .containsOnly(aragorn, frodo, legolas, boromir);
Filtering on a property or a field

First you specify the property/field name to filter on and then its expected value. The filter first tries to get the value from a property, then from a field. Reading private fields is supported by default, but can be disabled globally by calling Assertions.setAllowExtractingPrivateFields(false).

Filter supports nested properties/fields. Note that if an intermediate value is null the whole nested property/field is considered to be null, for example reading "address.street.name" will return null if "address.street" is null.

Filters support these basic operations: not, in, notIn

import static org.assertj.core.api.Assertions.in;
import static org.assertj.core.api.Assertions.not;
import static org.assertj.core.api.Assertions.notIn;
...

// filters use introspection to get property/field values
assertThat(fellowshipOfTheRing).filteredOn("race", HOBBIT)
                               .containsOnly(sam, frodo, pippin, merry);

// nested properties are supported
assertThat(fellowshipOfTheRing).filteredOn("race.name", "Man")
                               .containsOnly(aragorn, boromir);

// you can apply different comparison
assertThat(fellowshipOfTheRing).filteredOn("race", notIn(HOBBIT, MAN))
                               .containsOnly(gandalf, gimli, legolas);

assertThat(fellowshipOfTheRing).filteredOn("race", in(MAIA, MAN))
                               .containsOnly(gandalf, boromir, aragorn);

assertThat(fellowshipOfTheRing).filteredOn("race", not(HOBBIT))
                               .containsOnly(gandalf, boromir, aragorn, gimli, legolas);

// you can chain multiple filter criteria
assertThat(fellowshipOfTheRing).filteredOn("race", MAN)
                               .filteredOn("name", not("Boromir"))
                               .containsOnly(aragorn);
Filtering on a function return value

This is a more flexible way of getting the value to filter on but note that there is no support for operators like not, in and notIn.

assertThat(fellowshipOfTheRing).filteredOn(TolkienCharacter::getRace, HOBBIT)
                               .containsOnly(sam, frodo, pippin, merry);
Filtering on null value

Filters the elements whose specified property/field is null.

Filter supports nested properties/fields. Note that if an intermediate value is null the whole nested property/field is considered to be null, for example reading "address.street.name" will return null if "address.street" is null.

TolkienCharacter pippin = new TolkienCharacter("Pippin", 28, HOBBIT);
TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, HOBBIT);
TolkienCharacter merry = new TolkienCharacter("Merry", 36, HOBBIT);
TolkienCharacter mysteriousHobbit = new TolkienCharacter(null, 38, HOBBIT);

List<TolkienCharacter> hobbits = list(frodo, mysteriousHobbit, merry, pippin);

assertThat(hobbits).filteredOnNull("name"))
                   .singleElement()
                   .isEqualTo(mysteriousHobbit);
Filtering elements matching given assertions

Filters the iterable under test keeping only elements matching the given assertions specified with a Consumer.

Example: check hobbits whose age < 34

TolkienCharacter pippin = new TolkienCharacter("Pippin", 28, HOBBIT);
TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, HOBBIT);
TolkienCharacter merry = new TolkienCharacter("Merry", 36, HOBBIT);
TolkienCharacter sam = new TolkienCharacter("Sam", 38, HOBBIT);

List<TolkienCharacter> hobbits = list(frodo, sam, merry, pippin);

assertThat(hobbits).filteredOnAssertions(hobbit -> assertThat(hobbit.age).isLessThan(34))
                   .containsOnly(frodo, pippin);
Filtering with a Condition

Filter the iterable/array under test keeping only elements matching the given Condition.

Two methods are available: being(Condition) and having(Condition). They do the same job - pick the one that makes your code more readable!

import org.assertj.core.api.Condition;

Condition<Player> mvpStats= new Condition<Player>(player -> {
    return player.pointsPerGame() > 20 && (player.assistsPerGame() >= 8 || player.reboundsPerGame() >= 8);
  }, "mvp");

List<Player> players;
players.add(rose); // Derrick Rose: 25 ppg - 8 assists - 5 rebounds
players.add(lebron); // Lebron James: 27 ppg - 6 assists - 9 rebounds
players.add(noah); // Joachim Noah: 8 ppg - 5 assists - 11 rebounds

// noah does not have more than 20 ppg
assertThat(players).filteredOn(mvpStats)
                   .containsOnly(rose, lebron);

Let’s say you have called some service and got a list (or an array) of TolkienCharacter, to check the results you have to build the expected TolkienCharacters, that can be quite tedious!

List<TolkienCharacter> fellowshipOfTheRing = tolkienDao.findHeroes();  // frodo, sam, aragorn ...

// requires creation of frodo and aragorn, the expected TolkienCharacters
assertThat(fellowshipOfTheRing).contains(frodo, aragorn);

Instead, it is usually enough to check some fields or properties on the elements, for that you have to extract the fields/properties before performing your assertions, something like:

// extract the names ...
List<String> names = fellowshipOfTheRing.stream().map(TolkienCharacter::getName).collect(toList());
// ... and finally assert something
assertThat(names).contains("Boromir", "Gandalf", "Frodo", "Legolas");

This is too much work (even with the stream API), instead AssertJ can help extracting values from the elements under tests, there are several ways of doing so:

Specify the field/property to extract (or pass a Function) from each elements and perform assertions on the extracted values.

Extracting by name can access private fields/properties which is handy to check internals not exposed with public methods (lambda won’t work here), it also supports nested field/property like "race.name".

Examples:

// "name" needs to be either a property or a field of the TolkienCharacter class
assertThat(fellowshipOfTheRing).extracting("name")
                               .contains("Boromir", "Gandalf", "Frodo", "Legolas")
                               .doesNotContain("Sauron", "Elrond");

// specifying nested field/property is supported
assertThat(fellowshipOfTheRing).extracting("race.name")
                               .contains("Man", "Maia", "Hobbit", "Elf");

// same thing with a lambda which is type safe and refactoring friendly:
assertThat(fellowshipOfTheRing).extracting(TolkienCharacter::getName)
                               .contains("Boromir", "Gandalf", "Frodo", "Legolas");

// same thing map an alias of extracting:
assertThat(fellowshipOfTheRing).map(TolkienCharacter::getName)
                               .contains("Boromir", "Gandalf", "Frodo", "Legolas");

Note that extracting one property can be made strongly typed by giving the property type as the second argument.

// to have type safe extracting, use the second parameter to pass the expected property type:
assertThat(fellowshipOfTheRing).extracting("name", String.class)
                               .contains("Boromir", "Gandalf", "Frodo", "Legolas")
                               .doesNotContain("Sauron", "Elrond");

You can extract several values from the elements under test and check them using tuples.

As an example, let’s check the name, age and race’s name of each TolkienCharacter element:

// when checking several properties/fields you have to use tuples:
import static org.assertj.core.api.Assertions.tuple;

// extracting name, age and race.name nested property
assertThat(fellowshipOfTheRing).extracting("name", "age", "race.name")
                               .contains(tuple("Boromir", 37, "Man"),
                                         tuple("Sam", 38, "Hobbit"),
                                         tuple("Legolas", 1000, "Elf"));

// same assertion with functions for type safety:
assertThat(fellowshipOfTheRing).extracting(TolkienCharacter::getName,
                                            tolkienCharacter -> tolkienCharacter.age,
                                            tolkienCharacter -> tolkienCharacter.getRace().getName())
                                .contains(tuple("Boromir", 37, "Man"),
                                          tuple("Sam", 38, "Hobbit"),
                                          tuple("Legolas", 1000, "Elf"));

The extracted name, age and race’s name values of the current element are grouped in a tuple, thus you need to use tuples for specifying the expected values.

Flat extracting is hard to explain but easy to understand with an example, so let’s see how it works (in functional programming it is juts a flatMap).

Let’s assume we have a Player class with a teamMates property returning a List<Player> and we want to assert that it returns the expected players:

Player jordan = ... // initialized with Pippen and Kukoc team mates
Player magic = ... // initialized with Jabbar and Worthy team mates
List<Player> reallyGoodPlayers = list(jordan, magic);

// check all team mates by specifying the teamMates property (Player has a getTeamMates() method):
assertThat(reallyGoodPlayers).flatExtracting("teamMates")
                             .contains(pippen, kukoc, jabbar, worthy);

// alternatively, you can use a Function for type safety:
assertThat(reallyGoodPlayers).flatExtracting(BasketBallPlayer::getTeamMates)
                             .contains(pippen, kukoc, jabbar, worthy);

// flatMap is an alias of flatExtracting:
assertThat(reallyGoodPlayers).flatMap(BasketBallPlayer::getTeamMates)
                             .contains(pippen, kukoc, jabbar, worthy);

// if you use extracting instead of flatExtracting the result would be a list of list of players so the assertion becomes:
assertThat(reallyGoodPlayers).extracting("teamMates")
                             .contains(list(pippen, kukoc), list(jabbar, worthy));

| | You can use flatMap in place of flatExtracting (except for the variant taking a String) | | ------------------------------------------------------------------------------------------ |

Flat extracting can be used to group multiple values if you don’t want to use extracting and tuples:

// extract a list of values, flatten them and use contains assertion
assertThat(fellowshipOfTheRing).flatExtracting("name", "race.name")
                               .contains("Frodo", "Hobbit", "Legolas", "Elf");

// same assertions with Functions:
assertThat(fellowshipOfTheRing).flatExtracting(TolkienCharacter::getName,
                                               tc -> tc.getRace().getName())
                               .contains("Frodo", "Hobbit", "Legolas", "Elf");
Comparing elements with a specific comparator

usingElementComparator allows you to change the way elements are compared (instead of using the elements equals method).

Examples:

List<TolkienCharacter> fellowshipOfTheRing = list(frodo, sam, merry, pippin, gandald, legolas, boromir, aragorn, gimli);

// the fellowshipOfTheRing includes Gandalf but not Sauron ...
assertThat(fellowshipOfTheRing).contains(gandalf)
                               .doesNotContain(sauron);

// ... but if we compare only races, Sauron is in fellowshipOfTheRing since he's a Maia like Gandalf
assertThat(fellowshipOfTheRing).usingElementComparator((t1, t2) -> t1.getRace().compareTo(t2.getRace()))
                               .contains(sauron);

2.5.12. Exception assertions

This chapter answers the question: how to assert that an exception has been thrown and check that it is the expected one?

Reference

In this chapter the term exception is used interchangeably with throwable.

The next sections focus on some features worth knowing to get the best of AssertJ, notably:

If you use java 7, check the Java 7 section.

Checking exception message

There are various ways for checking the exception message content, you can check the exact message, what it contains, its start, its end, if it matches a regex.

Most of the assertions expecting a String can use the String.format syntax.

Examples:

Throwable throwable = new IllegalArgumentException("wrong amount 123");

assertThat(throwableWithMessage).hasMessage("wrong amount 123")
                                .hasMessage("%s amount %d", "wrong", 123)
                                // check start
                                .hasMessageStartingWith("wrong")
                                .hasMessageStartingWith("%s a", "wrong")
                                // check content
                                .hasMessageContaining("wrong amount")
                                .hasMessageContaining("wrong %s", "amount")
                                .hasMessageContainingAll("wrong", "amount")
                                // check end
                                .hasMessageEndingWith("123")
                                .hasMessageEndingWith("amount %s", "123")
                                // check with regex
                                .hasMessageMatching("wrong amount .*")
                                // check does not contain
                                .hasMessageNotContaining("right")
                                .hasMessageNotContainingAny("right", "price")
Checking the cause and root cause

There are two approaches to check the cause and root cause, either directly or navigate to it with cause() and rootCause() and check it.

Checking the cause

You can check the cause directly if you know it, but that’s not always possible, and in such cases you can only check its type. This is pretty limited in terms of assertions, a better approach is to navigate to the cause with cause() and take advantage of all existing exception assertions.

Direct cause assertions are limited …​

NullPointerException cause = new NullPointerException("boom!");
Throwable throwable = new Throwable(cause);

assertThat(throwable).hasCause(cause)
                     // hasCauseInstanceOf will match inheritance.
                     .hasCauseInstanceOf(NullPointerException.class)
                     .hasCauseInstanceOf(RuntimeException.class)
                     // hasCauseExactlyInstanceOf will match only exact same type
                     .hasCauseExactlyInstanceOf(NullPointerException.class);

... but navigating to the cause allows taking advantage of all exception assertions:

// navigate before checking
assertThat(throwable).cause()
                     .hasMessage("boom!")
                     .hasMessage("%s!", "boom")
                     .hasMessageStartingWith("bo")
                     .hasMessageEndingWith("!")
                     .hasMessageContaining("boo")
                     .hasMessageContainingAll("bo", "oom", "!")
                     .hasMessageMatching("b...!")
                     .hasMessageNotContaining("bam")
                     .hasMessageNotContainingAny("bam", "bim")
                     // isInstanceOf will match inheritance.
                     .isInstanceOf(NullPointerException.class)
                     .isInstanceOf(RuntimeException.class)
                     // isExactlyInstanceOf will match only exact same type
                     .isExactlyInstanceOf(NullPointerException.class);

An alternative is using assertThatExceptionOfType combined with havingCause as shown in the following example:

assertThatExceptionOfType(RuntimeException.class)
         .isThrownBy(() -> { throw new RuntimeException(new IllegalArgumentException("boom!")); })
         .havingCause()
         .withMessage("boom!");
Checking the root cause

You can check the root cause directly with hasRootCause, hasRootCauseMessage and hasRootCauseInstanceOf if you have access to it but that’s not always possible, this is a bit limited in terms of assertions, a better way is to navigate to the root cause with rootCause() and take advantage of all existing exception assertions.

Examples:

NullPointerException rootCause = new NullPointerException("null!");
Throwable throwable = new Throwable(new IllegalStateException(rootCause));

// direct root cause check
assertThat(throwable).hasRootCause(rootCause)
                     .hasRootCauseMessage("null!")
                     .hasRootCauseMessage("%s!", "null")
                     // hasRootCauseInstanceOf will match inheritance
                     .hasRootCauseInstanceOf(NullPointerException.class)
                     .hasRootCauseInstanceOf(RuntimeException.class)
                     // hasRootCauseExactlyInstanceOf will match only exact same type
                     .hasRootCauseExactlyInstanceOf(NullPointerException.class);

// navigate to root cause and check
assertThat(throwable).rootCause()
                     .hasMessage("null!")
                     .hasMessage("%s!", "null")
                     .hasMessageStartingWith("nu")
                     .hasMessageEndingWith("!")
                     .hasMessageContaining("ul")
                     .hasMessageContainingAll("nu", "ull", "l!")
                     .hasMessageMatching("n...!")
                     .hasMessageNotContaining("NULL")
                     .hasMessageNotContainingAny("Null", "NULL")
                     // isInstanceOf will match inheritance.
                     .isInstanceOf(NullPointerException.class)
                     .isInstanceOf(RuntimeException.class)
                     // isExactlyInstanceOf will match only exact same type
                     .isExactlyInstanceOf(NullPointerException.class);

An alternative is using assertThatExceptionOfType combined with havingRootCause as shown in the following example:

assertThatExceptionOfType(RuntimeException.class)
         .isThrownBy(() -> { throw new RuntimeException(new IllegalArgumentException(new NullPointerException("root error"))); })
         .havingRootCause()
         .withMessage("root error");
No cause

You can verify that a Throwable does not have a cause with hasNoCause().

BDD style

BDD aficionados can separate WHEN and THEN steps by using catchThrowable(ThrowingCallable) to capture the Throwable and then perform assertions (ThrowingCallable is a functional interface which can be expressed as a lambda).

Example:

// GIVEN
String[] names = { "Pier ", "Pol", "Jak" };
// WHEN
Throwable thrown = catchThrowable(() -> System.out.println(names[9]));
// THEN
then(thrown).isInstanceOf(ArrayIndexOutOfBoundsException.class)
            .hasMessageContaining("9");

// assertThat is also available but is less "BDD style"
assertThat(thrown).isInstanceOf(ArrayIndexOutOfBoundsException.class)
                  .hasMessageContaining("9");

| | catchThrowable returns null if no exception is thrown, but there is a better way to check that no exception is thrown. | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

catchThrowableOfType is a variation of catchThrowable where the caught exception type is verified and returned allowing to check the custom exception fields/properties.

Example:

class TextException extends Exception {
   int line;
   int column;

   public TextException(String msg, int line, int column) {
     super(msg);
     this.line = line;
     this.column = column;
   }
 }

 TextException textException = catchThrowableOfType(() -> { throw new TextException("boom!", 1, 5); },
                                                    TextException.class);
 // assertions succeed
 assertThat(textException).hasMessageContaining("boom");
 assertThat(textException.line).isEqualTo(1);
 assertThat(textException.column).isEqualTo(5);

 // fails as TextException is not a RuntimeException
 catchThrowableOfType(() -> { throw new TextException("boom!", 1, 5); }, RuntimeException.class);

Although the example above can be used for any exception type, enriched alternatives for catchThrowableOfType are also available to catch an instance of various commonly used exceptions:

For example, using catchIOException, the ThrowingCallable given as a parameter is executed: catchIOException returns null if no exception is thrown, otherwise it checks that the caught Throwable is of type IOException and casts it, making it convenient to perform subtype-specific assertions on it.

IOException iOException = catchIOException(() -> {throw new IOException("boom!");});
// assertions succeed
assertThat(iOException).hasMessage("boom!");

// succeeds as catchIOException returns null when the code does not throw any exceptions
assertThat(catchIOException(() -> {})).isNull();

// fails as the thrown instance is not an IOException
catchIOException(() -> {throw new Exception("boom!");});

The other catchXXX alternatives work the same way for their respective exception type.

assertThatThrownBy

assertThatThrownBy(ThrowingCallable) is an alternative to catchThrowable, use it if you find more readable.

Example:

assertThatThrownBy(() -> { throw new Exception("boom!"); }).isInstanceOf(Exception.class)
                                                           .hasMessageContaining("boom");

| | If the provided ThrowingCallable does not raise an exception, an assertion error is immediately thrown. | | ---------------------------------------------------------------------------------------------------------- |

assertThatExceptionOfType

assertThatExceptionOfType is an alternative syntax that some people find more natural.

assertThatExceptionOfType(IOException.class).isThrownBy(() -> { throw new IOException("boom!"); })
                                            .withMessage("%s!", "boom")
                                            .withMessageContaining("boom")
                                            .withNoCause();

| | If the provided ThrowingCallable does not raise an exception, an assertion error is immediately thrown. | | ---------------------------------------------------------------------------------------------------------- |

Similarly to catchThrowableOfType, the latter syntax has been enriched for commonly used exceptions:

The previous example can be rewritten as:

assertThatIOException().isThrownBy(() -> { throw new IOException("boom!"); })
                       .withMessage("%s!", "boom")
                       .withMessageContaining("boom")
                       .withNoCause();
Testing that no exception is thrown

You can test that a piece of code does not throw any exception with:

// standard style
assertThatNoException().isThrownBy(() -> System.out.println("OK"));
// BDD style
thenNoException().isThrownBy(() -> System.out.println("OK"));

or similarly:

// standard style
assertThatCode(() -> System.out.println("OK")).doesNotThrowAnyException();
// BDD style
thenCode(() -> System.out.println("OK")).doesNotThrowAnyException();
With Java 7 (AssertJ 2.x)

Asserting on exceptions is not as nice compared to the Java 8 way, this is how you would do it in AssertJ 2.x :

  1. Put the code that should throw the exception in a try-catch.
  2. Call fail method immediately after, so that the test fails if the exception is not thrown.
  3. Assert the caught exception.

Note that fail method can be statically imported from Assertions class.

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown;
// ... code omitted for brevity

assertThat(fellowshipOfTheRing).hasSize(9);

// here's the typical pattern to use Fail :
try {
  fellowshipOfTheRing.get(9); // argggl !
  // we should not arrive here => use fail to expresses that
  // if IndexOutOfBoundsException was not thrown, test would fail the specified message
  fail("IndexOutOfBoundsException expected because fellowshipOfTheRing has only 9 elements");
} catch (IndexOutOfBoundsException e) {
  assertThat(e).hasMessage("Index: 9, Size: 9");
}

// Warning: don't catch Throwable as it would also catch the AssertionError thrown by fail method

// another way to do the same thing
try {
  fellowshipOfTheRing.get(9); // argggl !
  // if IndexOutOfBoundsException was not thrown, test would fail with message :
  // "Expected IndexOutOfBoundsException to be thrown"
  failBecauseExceptionWasNotThrown(IndexOutOfBoundsException.class);
} catch (IndexOutOfBoundsException e) {
  assertThat(e).hasMessage("Index: 9, Size: 9");
}

2.5.13. Field by field recursive comparison

AssertJ Core provides a fluent recursive comparison API for Object assertions with the following capabilities:

The recursive comparison is meant to to replace isEqualToComparingFieldByFieldRecursively.

Basic usage

The recursive comparison mode starts after calling usingRecursiveComparison().

Here’s a simple example:

public class Person {
  String name;
  double height;
  Home home = new Home();
}

public class Home {
  Address address = new Address();
  Date ownedSince;
}

public static class Address {
  int number;
  String street;
}

Person sherlock = new Person("Sherlock", 1.80);
sherlock.home.ownedSince = new Date(123);
sherlock.home.address.street = "Baker Street";
sherlock.home.address.number = 221;

Person sherlock2 = new Person("Sherlock", 1.80);
sherlock2.home.ownedSince = new Date(123);
sherlock2.home.address.street = "Baker Street";
sherlock2.home.address.number = 221;

// assertion succeeds as the data of both objects are the same.
assertThat(sherlock).usingRecursiveComparison()
                    .isEqualTo(sherlock2);

// assertion fails as Person equals only compares references.
assertThat(sherlock).isEqualTo(sherlock2);

The comparison is not symmetrical since it is limited to actual fields.

The algorithm gathers actual fields and then compares them to the corresponding expected fields. It is then possible for the expected object to have more fields than actual, which can be handy when comparing a base type to a subtype with additional fields.

How field values are resolved

The recursive comparison uses introspection to find out the fields to compare and their values.

It first looks for the object under test fields (skipping any ignored ones as specified in the configuration), then it looks for the same fields in the expected object to compare to.

The next step is resolving the field values using first a getter method (if any) or reading the field value. The getter methods for a field x are getX() or isX() for boolean fields. If you enable bare properties resolution, a method x() is also used considered as a valid getter.

Bare name property is enabled by calling Assertions.setExtractBareNamePropertyMethods(true); (it is disabled by default since 3.18.0).

Lastly if the object under test is a map, the recursive comparison tries to resolve the field value by looking it up in the map with map.get(fieldName).

Since 3.24.0, you can specify your own strategy on how the recursive comparison resolve the values to compare, go to section specifying how to introspect the objects to compare for details.

Breaking changes

Since 3.18.0 bare name getter resolution are disabled by default, to get the previous behaviour back, call Assertions.setExtractBareNamePropertyMethods(true);

Since 3.17.0 it does not use anymore equals methods of classes that have overridden it, so no need to force recursive comparison on these classes. To get the previous behavior back, use usingOverriddenEquals().

isNotEqualTo

Since 3.17.0 isNotEqualTo is available in the recursive API, example:

// equals not overridden in TolkienCharacter
TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, HOBBIT);
TolkienCharacter frodoClone = new TolkienCharacter("Frodo", 33, HOBBIT);
TolkienCharacter youngFrodo = new TolkienCharacter("Frodo", 22, HOBBIT);

// Pass as equals compares object references
assertThat(frodo).isNotEqualTo(frodoClone);

// Fail as frodo and frodoClone are equals when doing a field by field comparison.
assertThat(frodo).usingRecursiveComparison()
                 .isNotEqualTo(frodoClone);

// Pass as one the age fields differ between frodo and youngFrodo.
assertThat(frodo).usingRecursiveComparison()
                 .isNotEqualTo(youngFrodo);
Strict or lenient comparison

By default the objects to compare can be of different types but must have the same properties/fields. For example if object under test has a work field of type Address, the expected object to compare the object under test to must also have one but it can of a different type like AddressDto.

It is possible to enforce strict type checking by calling withStrictTypeChecking() and make the comparison fail whenever the compared objects or their fields are not compatible. Compatible means that the expected object/field types are the same or a subtype of actual/field types, for example if actual is an Animal and expected a Dog, they will be compared field by field in strict type checking mode.

public class Person {
  String name;
  double height;
  Person bestFriend;
}

Person sherlock = new Person("Sherlock", 1.80);
sherlock.bestFriend = new Person("Watson", 1.70);

Person sherlockClone = new Person("Sherlock", 1.80);
sherlockClone.bestFriend = new Person("Watson", 1.70);

// assertion succeeds as sherlock and sherlockClone have the same data and types
assertThat(sherlock).usingRecursiveComparison()
                    .withStrictTypeChecking()
                    .isEqualTo(sherlockClone);

// Let's now define a data structure similar to Person

public class PersonDTO {
  String name;
  double height;
  PersonDTO bestFriend;
}

PersonDTO sherlockDto = new PersonDTO("Sherlock", 1.80);
sherlockDto.bestFriend = new PersonDTO("Watson", 1.70);

// assertion fails as Person and PersonDTO are not compatible even though they have the same data
assertThat(sherlock).usingRecursiveComparison()
                    .withStrictTypeChecking()
                    .isEqualTo(sherlockDto);

// Let's define a subclass of Person

public class Detective extends Person {
  boolean busy;
}

Detective detectiveSherlock = new Detective("Sherlock", 1.80);
detectiveSherlock.bestFriend = new Person("Watson", 1.70);
detectiveSherlock.busy = true;

// assertion succeeds as Detective inherits from Person and
// only Person's fields are included into the comparison.
assertThat(sherlock).usingRecursiveComparison()
                    .withStrictTypeChecking()
                    .isEqualTo(detectiveSherlock);
Ignoring fields in the comparison

It is possible to ignore fields of the object under test in the comparison, this is can be useful when a field has a generated value (like the current time) or is simply not relevant to compare.

There are a few ways to specify the fields to ignore:

Nested fields can be specified like this: home.address.street

It is also possible to ignore the object under test with ignoringActualNullFields().

Examples

Person sherlock = new Person("Sherlock", 1.80);
sherlock.home.address.street = "Baker Street";
sherlock.home.address.number = 221;

// strangely moriarty and sherlock have the same height!
Person moriarty = new Person("Moriarty", 1.80);
moriarty.home.address.street = "Crime Street";
moriarty.home.address.number = 221;

// assertion succeeds as name and home.address.street fields are ignored in the comparison
assertThat(sherlock).usingRecursiveComparison()
                    .ignoringFields("name", "home.address.street")
                    .isEqualTo(moriarty);

// assertion succeeds as once a field is ignored, its subfields are too
assertThat(sherlock).usingRecursiveComparison()
                    .ignoringFields("name", "home")
                    .isEqualTo(moriarty);

// ignoring fields matching regexes: name and home match .*me
assertThat(sherlock).usingRecursiveComparison()
                    .ignoringFieldsMatchingRegexes(".*me")
                    .isEqualTo(moriarty);

// ignoring null fields example:
sherlock.name = null;
sherlock.home.address.street = null;
assertThat(sherlock).usingRecursiveComparison()
                    .ignoringActualNullFields()
                    .isEqualTo(moriarty);

// ignore height and address fields by type:
Person tallSherlock = new Person("sherlock", 2.10);
tallSherlock.home.address.street = "Long Baker Street";
tallSherlock.home.address.number = 222;
assertThat(sherlock).usingRecursiveComparison()
                    .ignoringFieldsOfTypes(double.class, Address.class)
                    .isEqualTo(tallSherlock);
Using overridden equals

Since 3.17.0 the recursive comparison does not use overridden equals methods to compare fields anymore, it performs a recursive comparison on these fields, it is possible to change that behavior by calling usingOverriddenEquals().

Once using overridden equals methods is enabled, you can disable it for certain types or fields (and perform a recursive comparison instead) using the following methods:

Example:

public class Person {
  String name;
  double height;
  Home home = new Home();
}

public class Home {
  Address address = new Address();
}

public static class Address {
  int number;
  String street;

  // only compares number, ouch!
  @Override
  public boolean equals(final Object other) {
    if (!(other instanceof Address)) return false;
    Address castOther = (Address) other;
    return Objects.equals(number, castOther.number);
  }
}

Person sherlock = new Person("Sherlock", 1.80);
sherlock.home.address.street = "Baker Street";
sherlock.home.address.number = 221;

Person sherlock2 = new Person("Sherlock", 1.80);
sherlock2.home.address.street = "Butcher Street";
sherlock2.home.address.number = 221;

// assertion succeeds but that's not what we expected since the home.address.street fields differ
// but the equals implementation in Address does not compare them.
assertThat(sherlock).usingRecursiveComparison()
                    .usingOverriddenEquals()
                    .isEqualTo(sherlock2);

// to avoid the previous issue, we force a recursive comparison on the Address type
// now this assertion fails as expected since the home.address.street fields differ.
assertThat(sherlock).usingRecursiveComparison()
                    .usingOverriddenEquals()
                    .ignoringOverriddenEqualsForTypes(Address.class)
                    .isEqualTo(sherlock2);
Ignoring all expected null fields

By using ignoringExpectedNullFields() the recursive comparison will exclude from the comparison any null fields in the expected object.
One use case for that is when the object under test have fields with values hard to predict (id, timestamp, …​), with this feature you simply build the expected object with null values values for these fields and they won’t be compared.

Example:

public class Person {
  String name;
  double height;
  Home home = new Home();
}
public class Home {
  Address address = new Address();
}
public static class Address {
  int number;
  String street;
}

Person sherlock = new Person("Sherlock", 1.80);
sherlock.home.address.street = "Baker Street";
sherlock.home.address.number = 221;

Person noName = new Person(null, 1.80);
noName.home.address.street = null;
noName.home.address.number = 221;

// assertion succeeds as name and home.address.street fields are ignored in the comparison
assertThat(sherlock).usingRecursiveComparison()
                    .ignoringExpectedNullFields()
                    .isEqualTo(noName);

// assertion fails as name and home.address.street fields are populated for sherlock but not for noName.
assertThat(noName).usingRecursiveComparison()
                  .ignoringExpectedNullFields()
                  .isEqualTo(sherlock);
Ignoring all actual empty optional fields

ignoringActualEmptyOptionalFields() makes the recursive comparison to ignore all actual empty optional fields (including Optional, OptionalInt, OptionalLong and OptionalDouble).
Note that the expected object empty optional fields are not ignored, this only applies to actual’s fields.

public class Person {
  String name;
  OptionalInt age;
  OptionalLong id;
  OptionalDouble height;
  Home home = new Home();
}

public class Home {
  String address;
  Optional<String> phone;
}

Person homerWithoutDetails = new Person("Homer Simpson");
homerWithoutDetails.home.address.street = "Evergreen Terrace";
homerWithoutDetails.home.address.number = 742;
homerWithoutDetails.home.phone = Optional.empty();
homerWithoutDetails.age = OptionalInt.empty();
homerWithoutDetails.id = OptionalLong.empty();
homerWithoutDetails.height = OptionalDouble.empty();

Person homerWithDetails = new Person("Homer Simpson");
homerWithDetails.home.address.street = "Evergreen Terrace";
homerWithDetails.home.address.number = 742;
homerWithDetails.home.phone = Optional.of("(939) 555-0113");
homerWithDetails.age = OptionalInt.of(39);
homerWithDetails.id = OptionalLong.of(123456);
homerWithDetails.height = OptionalDouble.of(1.83);

// assertion succeeds as phone is ignored in the comparison
assertThat(homerWithoutDetails).usingRecursiveComparison()
                               .ignoringActualEmptyOptionalFields()
                               .isEqualTo(homerWithDetails);

// assertion fails as phone, age, id and height are not ignored and are populated for homerWithDetails but not for homerWithoutDetails.
assertThat(homerWithDetails).usingRecursiveComparison()
                            .ignoringActualEmptyOptionalFields()
                            .isEqualTo(homerWithoutDetails);
Specifying how to compare specific types or fields in the comparison

You can specify how to compare values per (nested) fields or type with the methods below (but before calling isEqualTo otherwise this has no effect!):

Note that comparisons specified for fields take precedence over the ones specified for types.

By default floats are compared with a precision of 1.0E-6 and doubles with 1.0E-15.

| | Prefer using withEqualsForFields/withEqualsForType, providing a BiPredicate is simpler than a Comparator (unless you have one already defined). | | -------------------------------------------------------------------------------------------------------------------------------------------------- |

Examples:

public class TolkienCharacter {
  String name;
  double height;
}

TolkienCharacter frodo = new TolkienCharacter("Frodo", 1.2);
TolkienCharacter tallerFrodo = new TolkienCharacter("Frodo", 1.3);
TolkienCharacter reallyTallFrodo = new TolkienCharacter("Frodo", 1.9);

BiPredicate<Double, Double> closeEnough = (d1, d2) -> Math.abs(d1 - d2) <= 0.5;
// same comparison expressed with a Comparator:
// Comparator<Double> closeEnough = (d1, d2) -> Math.abs(d1 - d2) <= 0.5 ? 0 : 1;

// assertion succeeds
assertThat(frodo).usingRecursiveComparison()
                 .withEqualsForFields(closeEnough, "height")
                 .isEqualTo(tallerFrodo);

assertThat(frodo).usingRecursiveComparison()
                 .withEqualsForType(closeEnough, Double.class)
                 .isEqualTo(tallerFrodo);

// assertions fail
assertThat(frodo).usingRecursiveComparison()
                 .withEqualsForFields(closeEnough, "height")
                 .isEqualTo(reallyTallFrodo);

assertThat(frodo).usingRecursiveComparison()
                 .withEqualsForType(closeEnough, Double.class)
                 .isEqualTo(reallyTallFrodo);
Overriding error messages for specific fields or types

If AssertJ difference error description is not yo your liking, you can override it either by fields or types.

You can override messages for all fields of a given type, example for Double:

withErrorMessageForType("Double field differ", Double.class)

Alternatively can override messages for some specific fields which must be specified from the root object, for example if Foo has a Bar field and both have an id field, one can register a message for Foo and Bar id by calling:

withErrorMessageForFields("id values differ", "foo.id", "foo.bar.id")

Messages registered with withErrorMessageForFields have precedence over the ones registered with withErrorMessageForType.

Example overriding message for a field:

public class TolkienCharacter {
  String name;
  double height;
}

TolkienCharacter frodo = new TolkienCharacter("Frodo", 1.2);
TolkienCharacter tallerFrodo = new TolkienCharacter("Frodon", 1.4);

String message = "The field 'height' differ.";

// assertion fails
assertThat(frodo).usingRecursiveComparison()
                 .withErrorMessageForFields(message, "height")
                 .isEqualTo(tallerFrodo);

and the error will report the height field with the given overridden message instead of the one computed by AssertJ as with the name error:

Expecting actual:
  TolkienCharacter [name=Frodo, height=1.2]
to be equal to:
  TolkienCharacter [name=Frodon, height=1.4]
when recursively comparing field by field, but found the following 2 differences:

The field 'height' differ.

field/property 'name' differ:
- actual value  : "Frodo"
- expected value: "Frodon"

The recursive comparison was performed with this configuration:
- no overridden equals methods were used in the comparison (except for java types)
- these types were compared with the following comparators:
  - java.lang.Double -> DoubleComparator[precision=1.0E-15]
  - java.lang.Float -> FloatComparator[precision=1.0E-6]
  - java.nio.file.Path -> lexicographic comparator (Path natural order)
- actual and expected objects and their fields were compared field by field recursively even if they were not of the same type, this allows for example to compare a Person to a PersonDto (call strictTypeChecking(true) to change that behavior).
- these fields had overridden error messages:
  - height

Example overriding message for a type:

String message = "Double field differ";

// assertion fails
assertThat(frodo).usingRecursiveComparison()
                 .withErrorMessageForType(message, Double.class)
                 .isEqualTo(tallerFrodo);

and the error will report the height field with the given overridden message instead of the one computed by AssertJ as with the name error:

Expecting actual:
  TolkienCharacter [name=Frodo, height=1.2]
to be equal to:
  TolkienCharacter [name=Frodon, height=1.4]
when recursively comparing field by field, but found the following 2 differences:

Double field differ.

field/property 'name' differ:
- actual value  : "Frodo"
- expected value: "Frodon"

The recursive comparison was performed with this configuration:
- no overridden equals methods were used in the comparison (except for java types)
- these types were compared with the following comparators:
  - java.lang.Double -> DoubleComparator[precision=1.0E-15]
  - java.lang.Float -> FloatComparator[precision=1.0E-6]
  - java.nio.file.Path -> lexicographic comparator (Path natural order)
- actual and expected objects and their fields were compared field by field recursively even if they were not of the same type, this allows for example to compare a Person to a PersonDto (call strictTypeChecking(true) to change that behavior).
- these types had overridden error messages:
  - height
Recursive comparison for iterable assertions

usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration) enables the recursive comparison for any iterable assertion as opposed to usingRecursiveComparison() which only allows isEqualTo and isNotEqualTo, the main difference between both isEqualTo assertions is that the usingRecursiveComparison one will give a detailed differences report while the usingRecursiveFieldByFieldElementComparator one will give a generic error message without details.

Another difference is that usingRecursiveComparison() exposes a fluent API to tweak the recursive comparison, to achieve the same you will need to initialize a RecursiveComparisonConfiguration and pass it to usingRecursiveFieldByFieldElementComparator, you can take advantage of the RecursiveComparisonConfiguration.builder() to do so.

Example:

public class Person {
  String name;
  boolean hasPhd;
}

public class Doctor {
  String name;
  boolean hasPhd;
}

Doctor drSheldon = new Doctor("Sheldon Cooper", true);
Doctor drLeonard = new Doctor("Leonard Hofstadter", true);
Doctor drRaj = new Doctor("Raj Koothrappali", true);

Person sheldon = new Person("Sheldon Cooper", false);
Person leonard = new Person("Leonard Hofstadter", false);
Person raj = new Person("Raj Koothrappali", false);
Person howard = new Person("Howard Wolowitz", false);

List<Doctor> doctors = list(drSheldon, drLeonard, drRaj);
List<Person> people = list(sheldon, leonard, raj);

RecursiveComparisonConfiguration configuration = RecursiveComparisonConfiguration.builder()
                                                                                 .withIgnoredFields("hasPhd")
                                                                                 .build();

// assertion succeeds as both lists contains equivalent items in order.
assertThat(doctors).usingRecursiveFieldByFieldElementComparator(configuration)
                   .contains(sheldon);

// assertion fails because leonard names are different.
leonard.setName("Leonard Ofstater");
assertThat(doctors).usingRecursiveFieldByFieldElementComparator(configuration)
                   .contains(leonard);

// assertion fails because howard is missing and leonard is not expected.
people = list(howard, sheldon, raj)
assertThat(doctors).usingRecursiveFieldByFieldElementComparator(configuration)
                   .contains(howard);
Specifying how to introspect the objects to compare

Since 3.24.0, you can specify your own strategy telling the recursive comparison how to resolve the values to compare, this is useful if the default strategy does not suit you.

To use your own introspection strategy, you need to:

AssertJ provides a few strategies out of the box:

ComparingSnakeOrCamelCaseFields is an example of ComparingNormalizedFields that normalizes snake case to camel case.

Here’s an example using ComparingSnakeOrCamelCaseFields where we compare Author/Book against AuthorDto/BookDto, Author/Book follow the regular camel case field naming convention while the dto classes follow the snake case naming convention.

The recursive comparison would fail comparing the Author/Book fields against AuthorDto/BookDto ones, it would not know to match Author.firstName against AuthorDto.first_name for example but with ComparingSnakeOrCamelCaseFields it will know how to match these fields.

Example:

Author martinFowler = new Author("Martin", "Fowler", 58, "https://www.thoughtworks.com/profiles/leaders/martin-fowler");
Book refactoring = new Book("Refactoring", martinFowler);
AuthorDto martinFowlerDto = new AuthorDto("Martin", "Fowler", 58, "https://www.thoughtworks.com/profiles/leaders/martin-fowler");
BookDto refactoringDto = new BookDto("Refactoring", martinFowlerDto);

RecursiveComparisonIntrospectionStrategy comparingSnakeOrCamelCaseFields = new ComparingSnakeOrCamelCaseFields();

// both assertions succeed
assertThat(refactoring).usingRecursiveComparison()
                      .withIntrospectionStrategy(comparingSnakeOrCamelCaseFields)
                      .isEqualTo(refactoringDto);
assertThat(refactoringDto).usingRecursiveComparison()
                          .withIntrospectionStrategy(comparingSnakeOrCamelCaseFields)
                          .isEqualTo(refactoring);

static class Author {
  String firstName;
  String lastName;
  int age;
  String profileURL;

  Author(String firstName, String lastName, int age, String profileUrl) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
    this.profileURL = profileUrl;
  }
}

static class Book {
  String title;
  Author mainAuthor;

  Book(String title, Author author) {
    this.title = title;
    this.mainAuthor = author;
  }
}
static class AuthorDto {
  String first_name;
  String last_name;
  int _age;
  String profile_url;

  AuthorDto(String firstName, String lastName, int age, String profileUrl) {
    this.first_name = firstName;
    this.last_name = lastName;
    this._age = age;
    this.profile_url = profileUrl;
  }
}

static class BookDto {
  String title;
  AuthorDto main_author;

  BookDto(String title, AuthorDto author) {
    this.title = title;
    this.main_author = author;
  }
}

2.5.14. Recursive assertions

The recursive assertion allFieldsSatisfy lets you verify a Predicate is met for all the fields of the object under test graph recursively (but not the object itself).

For example if the object under test is an instance of class A, A has a B field and B a C field then allFieldsSatisfy checks A’s B field and B’s C field and all C’s fields.

Example:

class Author {
  String name;
  String email;
  List<Book> books = new ArrayList<>();

  Author(String name, String email) {
    this.name = name;
    this.email = email;
  }
}

class Book {
  String title;
  Author[] authors;

  Book(String title, Author[] authors) {
    this.title = title;
    this.authors = authors;
  }
}

Author pramodSadalage = new Author("Pramod Sadalage", "p.sadalage@recursive.test");
Author martinFowler = new Author("Martin Fowler", "m.fowler@recursive.test");
Author kentBeck = new Author("Kent Beck", "k.beck@recursive.test");

Book noSqlDistilled = new Book("NoSql Distilled", new Author[] {pramodSadalage, martinFowler});
pramodSadalage.books.add(noSqlDistilled);
martinFowler.books.add(noSqlDistilled);

Book refactoring = new Book("Refactoring", new Author[] {martinFowler, kentBeck});
martinFowler.books.add(refactoring);
kentBeck.books.add(refactoring);

// assertion succeeds
assertThat(pramodSadalage).usingRecursiveAssertion()
                          .allFieldsSatisfy(field -> field != null);

The above example is best rewritten with hasNoNullFields() which is common enough that it is supported out of the box.

The recursive assertion provides these methods to exclude fields, the predicate won’t be applied on the excluded fields:

2.5.15. Soft assertions

With soft assertions AssertJ collects all assertion errors instead of stopping at the first one.

| | This is especially useful for long tests like end to end tests as we can fix all reported errors at once and avoid multiple failing runs. | | -------------------------------------------------------------------------------------------------------------------------------------------- |

Since soft assertions don’t fail at the first error, you need to tell AssertJ when to report the captured assertion errors, there are different ways of doing so:

Soft assertions comes with a BDD flavor where assertThat is replaced by then.

If you have created your own custom Soft assertions it is possible to combine them all in a single soft assertions entry point.

Let’s see first how to use soft assertions requiring an explicit call to assertAll(), the other approaches that don’t require this explicitit call are described in the subsequent sections.

Example:

@Test
void basic_soft_assertions_example() {
  SoftAssertions softly = new SoftAssertions(); (1)

  softly.assertThat("George Martin").as("great authors").isEqualTo("JRR Tolkien");  (2)
  softly.assertThat(42).as("response to Everything").isGreaterThan(100); (2)
  softly.assertThat("Gandalf").isEqualTo("Sauron"); (2)

  // Don't forget to call assertAll() otherwise no assertion errors are reported!
  softly.assertAll(); (3)
}
1 Build a SoftAssertions instance to record all assertion errors
2 Use softly.assertThat instead of the usual assertThat methods
3 Don’t forget to call assertAll() to report all assertion errors!

The previous test fails with the message below reporting all the errors:

Multiple Failures (3 failures)
-- failure 1 --
[great authors]
Expecting:
 <"George Martin">
to be equal to:
 <"JRR Tolkien">
but was not.
-- failure 2 --
[response to Everything]
Expecting:
 <42>
to be greater than:
 <100>
-- failure 3 --
Expecting:
 <"gandalf">
to be equal to:
 <"sauron">
but was not.
BDD Soft assertions

BDD aficionados can use BDD soft assertions where assertThat is replaced by then.

Example:

@Test
void basic_bdd_soft_assertions_example() {
  BDDSoftAssertions softly = new BDDSoftAssertions();

  softly.then("George Martin").as("great authors").isEqualTo("JRR Tolkien");
  softly.then(42).as("response to Everything").isGreaterThan(100);
  softly.then("Gandalf").isEqualTo("Sauron");

  // Don't forget to call assertAll() otherwise no assertion errors are reported!
  softly.assertAll();
}

There are BDD soft assertions versions for the different soft assertions approaches:

JUnit 4 Soft assertions rule

The JUnit rule provided by AssertJ takes care of calling assertAll() at the end of each tests.

Example:

@Rule
public final JUnitSoftAssertions softly = new JUnitSoftAssertions();

@Test
void junit4_soft_assertions_example() {
  softly.assertThat("George Martin").as("great authors").isEqualTo("JRR Tolkien");  (2)
  softly.assertThat(42).as("response to Everything").isGreaterThan(100); (2)
  softly.assertThat("Gandalf").isEqualTo("Sauron"); (2)
  // No need to call softly.assertAll(), this is automatically done by the JUnitSoftAssertions rule
}

In a similar way you can use JUnitBDDSoftAssertions where assertThat is replaced by then:

@Rule
public final JUnitBDDSoftAssertions softly = new JUnitBDDSoftAssertions();

@Test
void junit4_bdd_soft_assertions_example() {
  softly.then("George Martin").as("great authors").isEqualTo("JRR Tolkien");
  softly.then(42).as("response to Everything").isGreaterThan(100);
  softly.then("Gandalf").isEqualTo("Dauron");
  // No need to call softly.assertAll(), this is automatically done by the JUnitSoftAssertions rule
}
JUnit 5 soft assertions extension

SoftAssertionsExtension is a JUnit 5 extension that:

SoftAssertionsProvider is the interface that any concrete soft assertions class must implement, AssertJ provides two of them: SoftAssertions and BDDSoftAssertions, but custom implementations are also supported as long as they have a default constructor. See the end of combining soft assertions entry points section for an example.

| | JUnitJupiterSoftAssertions, JUnitJupiterBDDSoftAssertions and SoftlyExtension are now deprecated in favor of SoftAssertionsExtension. | | ---------------------------------------------------------------------------------------------------------------------------------------- |

SoftAssertionsProvider field injection

SoftAssertionsExtension supports injecting any instance of SoftAssertionsProvider into a class test field annotated with @InjectSoftAssertions.
The injection occurs before each test method execution, after each test assertAll() is invoked to verify that no soft assertions failed.

A nested test class can provide a SoftAssertionsProvider field when it extends this extension or can inherit the parent’s one.

You can have multiple soft assertion providers injected into a single test class. Assertions made on any of them will be collected in a single error collector and reported all together, in the same order that they failed.

This extension throws an ExtensionConfigurationException if:

Example:

import org.assertj.core.api.SoftAssertions;
import org.assertj.core.api.junit.jupiter.SoftAssertionsExtension;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

@ExtendWith(SoftAssertionsExtension.class)
public class JUnit5SoftAssertionsExtensionAssertionsExamples {

  @InjectSoftAssertions
  private SoftAssertions softly;

  @Test
  public void chained_soft_assertions_example() {
    String name = "Michael Jordan - Bulls";
    softly.assertThat(name).startsWith("Mi")
                           .contains("Bulls");
    // no need to call softly.assertAll(), this is done by the extension
  }

  // nested classes test work too
  @Nested
  class NestedExample {

    @Test
    public void football_assertions_example() {
      String kylian = "Kylian Mbappé";
      softly.assertThat(kylian).startsWith("Ky")
                               .contains("bap");
      // no need to call softly.assertAll(), this is done by the extension
    }
  }
}
SoftAssertionsProvider parameter injection

SoftAssertionsExtension supports injecting any SoftAssertionsProvider implementation as a parameter in any test method.

The term "test method" refers to any method annotated with @Test, @RepeatedTest, @ParameterizedTest, @TestFactory or @TestTemplate. Notably, the extension is compatible with parameterized tests, the parameterized arguments must come first and the soft assertions argument last.

The scope of the SoftAssertionsProvider instance managed by this extension begins when a parameter of type SoftAssertionsProvider is resolved for a test method.
It ends after the test method has been executed, this is when assertAll() will be invoked on the instance to verify that no soft assertions failed.

Parameter injection and field injection can be mixed. Assertions made on the field- and parameter-injected soft assertion providers will all be collected and reported together when the extension calls assertAll().

This extension throws a ParameterResolutionException if the resolved SoftAssertionsProvider :

Example:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.api.extension.ExtendWith;
import org.assertj.core.api.BDDSoftAssertions;
import org.assertj.core.api.SoftAssertions;
import org.assertj.core.api.junit.jupiter.SoftAssertionsExtension;

@ExtendWith(SoftAssertionsExtension.class)
public class JUnit5SoftAssertionsExample {

  @Test
  void junit5_soft_assertions_multiple_failures_example(SoftAssertions softly) {
    softly.assertThat("George Martin").as("great authors").isEqualTo("JRR Tolkien");
    softly.assertThat(42).as("response to Everything").isGreaterThan(100);
    softly.assertThat("Gandalf").isEqualTo("Sauron");
    // No need to call softly.assertAll(), this is automatically done by the SoftAssertionsExtension
  }

  @Test
  void junit5_bdd_soft_assertions_multiple_failures_example(BDDSoftAssertions softly) {
    softly.then("George Martin").as("great authors").isEqualTo("JRR Tolkien");
    softly.then(42).as("response to Everything").isGreaterThan(100);
    softly.then("Gandalf").isEqualTo("Sauron");
    // No need to call softly.assertAll(), this is automatically done by the SoftAssertionsExtension
  }

  @ParameterizedTest
  @CsvSource({ "1, 1, 2", "1, 2, 3" })
  // test parameters come first, soft assertion must come last.
  void junit5_soft_assertions_parameterized_test_example(int a, int b, int sum, SoftAssertions softly) {
    softly.assertThat(a + b).as("sum").isEqualTo(sum);
    softly.assertThat(a).isLessThan(sum);
    softly.assertThat(b).isLessThan(sum);
  }

}
Auto Closeable Soft assertions

As AutoCloseableSoftAssertions implements AutoCloseable#close() by calling assertAll(), when used in a try-with-resources block assertAll() is called automatically before exiting the block.

Example:

@Test
void auto_closeable_soft_assertions_example() {
  try (AutoCloseableSoftAssertions softly = new AutoCloseableSoftAssertions()) {
  softly.assertThat("George Martin").as("great authors").isEqualTo("JRR Tolkien");  (2)
  softly.assertThat(42).as("response to Everything").isGreaterThan(100); (2)
  softly.assertThat("Gandalf").isEqualTo("Sauron"); (2)
    // no need to call assertAll, this is done when softly is closed.
  }
}

In a similar way you can use AutoCloseableBDDSoftAssertions where assertThat is replaced by then:

@Test
void auto_closeable_bdd_soft_assertions_example() {
  try (AutoCloseableBDDSoftAssertions softly = new AutoCloseableBDDSoftAssertions()) {
    softly.then("George Martin").as("great authors").isEqualTo("JRR Tolkien");
    softly.then(42).as("response to Everything").isGreaterThan(100);
    softly.then("Gandalf").isEqualTo("Sauron");
    // no need to call assertAll, this is done when softly is closed.
  }
}
Soft assertions with assertSoftly

The assertSoftly static method takes care of calling assertAll() before exiting.

Example:

@Test
void assertSoftly_example() {
  SoftAssertions.assertSoftly(softly -> {
    softly.assertThat("George Martin").as("great authors").isEqualTo("JRR Tolkien");
    softly.assertThat(42).as("response to Everything").isGreaterThan(100);
    softly.assertThat("Gandalf").isEqualTo("Sauron");
    // no need to call assertAll(), assertSoftly does it for us.
  });
}
Combining soft assertions entry points

Since the 3.16.0 version AssertJ provides a way to combine standard soft assertions with custom ones in a single entry point.

Let’s assume we have written an entry point for TolkienCharacter soft assertions so that we can write assertions like:

TolkienSoftAssertions softly = new TolkienSoftAssertions();
softly.assertThat(frodo).hasRace(HOBBIT)
                        .hasName("Frodo");

If we want to check standard soft assertions we could make TolkienSoftAssertions inherit SoftAssertions but if we want to have GoTSoftAssertions too then we are stuck as Java does not allow multiple inheritance.

The 3.16.0 release introduced the SoftAssertionsProvider interface to define soft assertions entry points.

Step 1
The first step consists in extending this interface to expose as many custom entry points as you need.
The typical custom SoftAssertionsProvider interface exposes default assertThat methods, as shown below:

public interface TolkienSoftAssertionsProvider extends SoftAssertionsProvider {
  // custom assertions
  default TolkienCharacterAssert assertThat(TolkienCharacter actual) {
    return proxy(TolkienCharacterAssert.class, TolkienCharacter.class, actual);
  }
}

// let's add a Game of Thrones entry point
public interface GoTSoftAssertionsProvider extends SoftAssertionsProvider {
  // custom assertions
  default GoTCharacterAssert assertThat(GoTCharacter actual) {
    return proxy(GoTCharacterAssert.class, GoTCharacter.class, actual);
  }
}

Step 2
In order to get a concrete entry point exposing all custom entry points, create a class implementing all custom SoftAssertionsProvider subinterfaces and extending AbstractSoftAssertions.AbstractSoftAssertions provides the core internal implementation to collect all errors from the different implemented entry points (it also implements SoftAssertionsProvider).

To get standard soft assertions, inherit from SoftAssertions instead of AbstractSoftAssertions (or BddSoftAssertions to get the BDD flavor).

Let’s define our concrete entry points implementing both TolkienSoftAssertionsProvider and GoTSoftAssertionsProvider:

// we extend SoftAssertions to get standard soft assertions
public class FantasySoftAssertions extends SoftAssertions
                                   implements TolkienSoftAssertionsProvider, GoTSoftAssertionsProvider {

  // we can even add more assertions here
  public HumanAssert assertThat(Human actual) {
    return proxy(HumanAssert.class, Human.class, actual);
  }
}

Step 3
The last step is to use FantasySoftAssertions:

FantasySoftAssertions softly = new FantasySoftAssertions();

// custom TolkienCharacter assertions
softly.assertThat(frodo).hasRace(HOBBIT);

// custom GoTCharacter assertions
softly.assertThat(nedStark).isDead();

// standard assertions
softly.assertThat("Games of Thrones").startsWith("Games")
                                     .endsWith("Thrones");
// verify assertions
softly.assertAll();

Optional step: create a custom JUnit 4 Rule

Because our custom assertions are defined in an interface, we can also combine them with AssertJ’s JUnit 4 rule so that we can use our custom assertions as a test rule for use in JUnit 4:

// we extend JUnitSoftAssertions to get standard soft assertions classes
public class JUnitFantasySoftAssertions extends JUnitSoftAssertions
                                   implements TolkienSoftAssertionsProvider, GoTSoftAssertionsProvider {}

Then in our test class we use it per normal:

public class JUnit4_StandardAndCustomSoftAssertionsExamples {
  @Rule
  public final JUnitFantasySoftAssertions softly = new JUnitFantasySoftAssertions();

  @Test
  public void successful_junit_soft_custom_assertion_example() {
    softly.assertThat(frodo).hasName("Frodo")
                            .hasAge(33);
    softly.assertThat(frodo.age).isEqualTo(33);
  }
}

The rule will automatically take care of calling assertAll() at the end of every test.

Optional step: use SoftAssertionsExtension

JUnit 5 SoftAssertionsExtension calls softly.assertAll() after each test so that we don’t have to do it manually.
Since 3.16.0 it is capable of injecting any SoftAssertionsProvider, we can then inject our custom FantasySoftAssertions:

@ExtendWith(SoftAssertionsExtension.class)
public class JUnit5_StandardAndCustomSoftAssertionsExamples {

  @Test
  public void successful_junit_soft_custom_assertion_example(FantasySoftAssertions softly) {
    softly.assertThat(frodo).hasName("Frodo")
                            .hasAge(33);
    softly.assertThat(frodo.age).isEqualTo(33);
  }
}
Reacting to collected soft assertions

AssertJ allows to perform an action after an AssertionError is collected.

The action is specified by the AfterAssertionErrorCollected functional interface which can be expressed as lambda, to register your callback call setAfterAssertionErrorCollected as shown below:

Example:

SoftAssertions softly = new SoftAssertions();
StringBuilder reportBuilder = new StringBuilder(format("Assertions report:%n"));

// register our callback
softly.setAfterAssertionErrorCollected(error -> reportBuilder.append(format("------------------%n%s%n", error.getMessage())));
// the AssertionError corresponding to the failing assertions are registered in the report
softly.assertThat("The Beatles").isEqualTo("The Rolling Stones");
softly.assertThat(123).isEqualTo(123)
                      .isEqualTo(456);

resulting reportBuilder:

Assertions report:
------------------
Expecting:
 <"The Beatles">
to be equal to:
 <"The Rolling Stones">
but was not.
------------------
Expecting:
 <123>
to be equal to:
 <456>
but was not.

Alternatively, if you have defined your own SoftAssertions class and inherited from AbstractSoftAssertions, you can instead override onAssertionErrorCollected(AssertionError).

Example:

class TolkienSoftAssertions extends AbstractSoftAssertions {

  public TolkienHeroesAssert assertThat(TolkienHero actual) {
    return proxy(TolkienHeroesAssert.class, TolkienHero.class, actual);
  }

  @Override
  public void onAssertionErrorCollected(AssertionError assertionError) {
    System.out.println(assertionError);
  }
}

TolkienSoftAssertions softly = new TolkienSoftAssertions();

TolkienCharacter frodo = TolkienCharacter.of("Frodo", 33, HOBBIT);

// the AssertionError corresponding to this failing assertion is printed to the console.
softly.assertThat(frodo).hasName("Bilbo");

2.5.16. Assumptions

Assumptions provide support for conditional test execution, if the assumptions are met the test is executed normally, if they don’t the test is aborted and marked as ignored.

Assumptions are typically used whenever it does not make sense to continue execution of a given test method — a typical usage is running tests depending on a given OS/environment.

All AssertJ assumptions are static methods in the Assumptions class, they match the assertion API but are names assumeThat instead of assertThat. You can also get assumptions through the WithAssumptions interface.

Example resulting in the test to be ignored:

@Test
public void when_an_assumption_is_not_met_the_test_is_ignored() {
  // since this assumption is obviously false ...
  assumeThat(frodo.getRace()).isEqualTo(ORC);
  // ... this assertion is not performed
  assertThat(fellowshipOfTheRing).contains(sauron);
}

Example resulting in the test to be executed normally:

@Test
public void when_all_assumptions_are_met_the_test_is_run_normally() {
  // since this assumption is true ...
  assumeThat(frodo.getRace()).isEqualTo(HOBBIT);
  // ... this assertion is performed
  assertThat(fellowshipOfTheRing).doesNotContain(sauron);
}

2.6. Extending assertions

AssertJ can be extends by Condition or writing your own assertions class.

2.6.1. Conditions

Assertions can be extended by using conditions, to create a condition you just have to implement org.assertj.assertions.core.Condition and its unique method matches.

Once your Condition is created, you can use it with methods: is(myCondition) or has(myCondition), both verifying that the condition is met (hint: pick the one that makes your code more readable).

Example:

// jedi is a Condition
assertThat("Yoda").is(jedi);

Conditions can be combined with :

You can verify that a Condition is met on elements of a collection, with the following methods:

Moreover all Condition related methods have their negation counterpart, is/isNot, have/doesNotHave, are/areNot, …​

Creating a Condition

Let’s define two similar conditions: jedi and jediPower with the same implementation to show that code readability is better when using jedi with is and jediPower with has.

import static org.assertj.core.util.Sets.newLinkedHashSet;

static Set<String> JEDIS = newLinkedHashSet("Luke", "Yoda", "Obiwan");

// implementation with Java 8 lambda
Condition<String> jediPower = new Condition<>(JEDIS::contains, "jedi power");

// implementation with Java 7
Condition<String> jedi = new Condition<String>("jedi") {
  @Override
  public boolean matches(String value) {
    return JEDIS.contains(value);
  }
};

The String parameter is describing the condition, this is used in error messages.

Using Conditions

Usage with single instances:

assertThat("Yoda").is(jedi);
assertThat("Vader").isNot(jedi);

assertThat("Yoda").has(jediPower);
assertThat("Solo").doesNotHave(jediPower);

The Condition description is used in error messages, ex:

assertThat("Vader").is(jedi);

will fail with the following error message:

"expecting:<'Vader'> to be:<jedi>"

Usage with collections:

assertThat(list("Luke", "Yoda")).are(jedi);
assertThat(list("Leia", "Solo")).areNot(jedi);

assertThat(list("Luke", "Yoda")).have(jediPower);
assertThat(list("Leia", "Solo")).doNotHave(jediPower);

assertThat(list("Luke", "Yoda", "Leia")).areAtLeast(2, jedi);
assertThat(list("Luke", "Yoda", "Leia")).haveAtLeast(2, jediPower);

assertThat(list("Luke", "Yoda", "Leia")).areAtMost(2, jedi);
assertThat(list("Luke", "Yoda", "Leia")).haveAtMost(2, jediPower);

assertThat(list("Luke", "Yoda", "Leia")).areExactly(2, jedi);
assertThat(list("Luke", "Yoda", "Leia")).haveExactly(2, jediPower);
Combining Conditions

Conditions can be combined with allOf(Condition…​) (logical and) or anyOf(Condition…​) (logical or), not can be used to invert one.

Let’s define a sith condition:

List<String> SITHS = list("Sidious", "Vader", "Plagueis");
Condition<String> sith = new Condition<>(SITHS::contains, "sith");

We can write these assertions:

assertThat("Vader").is(anyOf(jedi, sith));
assertThat("Solo").is(allOf(not(jedi), not(sith)));

2.6.2. Custom Assertions

Creating assertions specific to your own classes is interesting because these assertions will reflect the domain model. It’s a way to use Domain Driven Design ubiquitous language in your tests.

Writing your own assertions is simple: create a class inheriting from AbstractAssert and add your custom assertions methods.

| | Add a static method assertThat to provide a handy entry point to your new assertion class. | | --------------------------------------------------------------------------------------------- |

Sections:

Creating your own assertion class

Let’s see how to do that with an example!

We want to have assertion for the TolkienCharacter domain model class shown below:

// getter/setter omitted for brevity
public class TolkienCharacter {
  private String name;
  private Race race; // Race is an enum
  private int age;
}

Let’s name our assertion class TolkienCharacterAssert, we make it inherit from AbstractAssert and specify two generic parameters: the first is the class itself (needed for assertion chaining) and the second is the class we want to make assertions on: TolkienCharacter.

Inheriting from AbstractAssert will give you all the basic assertions: isEqualTo, isNull, satisfies, …​

public class TolkienCharacterAssert extends AbstractAssert<TolkienCharacterAssert, TolkienCharacter> { (1)

  public TolkienCharacterAssert(TolkienCharacter actual) { (2)
    super(actual, TolkienCharacterAssert.class);
  }

  public static TolkienCharacterAssert assertThat(TolkienCharacter actual) { (3)
    return new TolkienCharacterAssert(actual);
  }

  public TolkienCharacterAssert hasName(String name) { (4)
    // check that actual TolkienCharacter we want to make assertions on is not null.
    isNotNull();
    // check assertion logic
    if (!Objects.equals(actual.getName(), name)) {
      failWithMessage("Expected character's name to be <%s> but was <%s>", name, actual.getName());
    }
    // return this to allow chaining other assertion methods
    return this;
  }

  public TolkienCharacterAssert hasAge(int age) { (4)
    // check that actual TolkienCharacter we want to make assertions on is not null.
    isNotNull();
    // check assertion logic
    if (actual.getAge() != age) {
      failWithMessage("Expected character's age to be <%s> but was <%s>", age, actual.getAge());
    }
    // return this to allow chaining other assertion methods
    return this;
  }
}
1 Inherits from AbstractAssert
2 Constructor to build your assertion class with the object under test
3 An entry point to your specific assertion class to use with static import
4 assertions specific to TolkienCharacter
Using our custom assertion class

To use our custom assertion class, simply call the assertThat factory method with the object to test:

// use assertThat from TolkienCharacterAssert to check TolkienCharacter
TolkienCharacterAssert.assertThat(frodo).hasName("Frodo");

// code is more elegant when TolkienCharacterAssert.assertThat is imported statically :
assertThat(frodo).hasName("Frodo");

Well, that was not too difficult, but having to add a static import for each assertThat method of you custom assertion classes is not very handy, it would be better to have a unique assertion entry point. This is what we are going to do in the next section.

Providing an entry point for all custom assertions

Now that you have a bunch of custom assertions classes, you want to access them easily. Just create a CustomAssertions class providing static assertThat methods for each of your assertions classes.

Example:

public class MyProjectAssertions {

  // give access to TolkienCharacter assertion
  public static TolkienCharacterAssert assertThat(TolkienCharacter actual) {
    return new TolkienCharacterAssert(actual);
  }

  // give access to TolkienCharacter Race assertion
  public static RaceAssert assertThat(Race actual) {
    return new RaceAssert(actual);
  }
}

Usage:

import static my.project.MyProjectAssertions.assertThat;
import static org.assertj.core.api.Assertions.assertThat;
...

@Test
public void successful_custom_assertion_example() {
  // assertThat(TolkienCharacter) comes from my.project.MyProjectAssertions.assertThat
  assertThat(frodo).hasName("Frodo");

  // assertThat(String) comes from org.assertj.core.api.Assertions.assertThat
  assertThat("frodo").contains("do");
}

| | You could also make your custom Assertions entry point class inherit AssertJ’s Assertions, that will work fine if and only if you have one entry point class for your custom assertions classes! | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

The problem with several entry point classes inheriting from AssertJ Assertions, then when you use them Java won’t be able to resolve which assertThat(String) method to use. The following code illustrates the issue:

// both MyAssertions and MyOtherAssertions inherit from org.assertj.core.api.Assertions
import static my.project.MyAssertions.assertThat;
import static my.project.MyOtherAssertions.assertThat;
...

@Test
public void ambiguous_assertThat_resolution() {
  // ERROR: assertThat(String) is ambiguous!
  // assertThat(String) is available from MyAssertions AND MyOtherAssertions
  // (it is defined in Assertions the class both MyAssertions and MyOtherAssertions inherits from)
  assertThat("frodo").contains("do");
}

2.7. Migrating assertions

This page will help you convert your existing JUnit assertions to AssertJ ones. Note that both types of assertions can coexist, you don’t have to migrate all at once.

The idea is to convert code like:

assertEquals(expected, actual);

to:

assertThat(actual).isEqualTo(expected);

There are several ways to perform the conversion :

The preferred approach is to use the provided migration scripts or OpenRewrite recipes as they are type safe and cover more assertions than the other ones.

2.7.1. Migration Scripts

It is as simple as running one of the following scripts depending on which test framework you are using:

Each shell script is based on the sed stream editor and regexps. It recursively looks at all *Test.java files and performs search and replace to convert assertions to AssertJ ones.

The script handles the cases where you use an assertion description, for example:

assertEquals("test context", "a", "a");

will be replaced by:

assertThat("a").as("test context").isEqualTo("a");

Note that the script does a best effort and some assertions might not be converted if formatted on multiple lines. Anyway the script usually migrates the vast majority of assertions.

The script works on Windows within a bash console like git bash (tested a long time ago) or cygwin (not tested).

Usage

Execute the script in the base directory containing the test files:

cd ./src/test/java
./convert-junit-assertions-to-assertj.sh

If the *Test.java file pattern does not suit you, just specify another as an argument:

# enclose your pattern with double quotes "" to avoid it to be expanded by your shell prematurely
./convert-junit-assertions-to-assertj.sh "*IT.java"

After executing it, you will need to :

Script output
Converting JUnit assertions to AssertJ assertions on files matching pattern : *Test.java

 1 - Replacing : assertEquals(0, myList.size()) ............... by : assertThat(myList).isEmpty()
 2 - Replacing : assertEquals(expectedSize, myList.size()) .... by : assertThat(myList).hasSize(expectedSize)
 3 - Replacing : assertEquals(expectedDouble, actual, delta) .. by : assertThat(actual).isCloseTo(expectedDouble, within(delta))
 4 - Replacing : assertEquals(expected, actual) ............... by : assertThat(actual).isEqualTo(expected)
 5 - Replacing : assertArrayEquals(expectedArray, actual) ..... by : assertThat(actual).isEqualTo(expectedArray)
 6 - Replacing : assertNull(actual) ........................... by : assertThat(actual).isNull()
 7 - Replacing : assertNotNull(actual) ........................ by : assertThat(actual).isNotNull()
 8 - Replacing : assertTrue(logicalCondition) ................. by : assertThat(logicalCondition).isTrue()
 9 - Replacing : assertFalse(logicalCondition) ................ by : assertThat(logicalCondition).isFalse()
10 - Replacing : assertSame(expected, actual) ................. by : assertThat(actual).isSameAs(expected)
11 - Replacing : assertNotSame(expected, actual) .............. by : assertThat(actual).isNotSameAs(expected)

Replacing JUnit static imports by AssertJ ones, at this point you will probably need to :
12 --- optimize imports with your IDE to remove unused imports
12 --- add "import static org.assertj.core.api.Assertions.within;" if you were using JUnit number assertions with deltas

2.7.2. OpenRewrite

OpenRewrite, a large-scale automated source code refactoring tool, offers a couple of recipes that assist with the migration to AssertJ:

If you want to go even further, you can run the AssertJ best practices recipe which will do all of the above plus:

2.7.3. Migration Regexes

Here’s a list of find/replace expressions to change JUnit assertions into AssertJ assertions (don’t forget to check the regex mode in your editor replace window).

These regexes described in this section are specific to JUnit 4, but you can easily adapt them for JUnit 5 or TestNG.

The order of find/replace is important to benefit from the most relevant AssertJ assertions. For example, you should convert assertEquals(0, myList.size()) to assertThat(myList).isEmpty() instead of assertThat(myList.size()).isEqualTo(0).

Converting assertEquals(0, myList.size()) to assertThat(myList).isEmpty()

Find/replace regex:

assertEquals\(0,(.*).size\(\)\); -> assertThat(\1).isEmpty();

It’s better to run this before the assertEqualsisEqualTo conversion to avoid ending with assertThat(myList.size()).isEqualTo(0).

Converting assertEquals(size, myList.size()) to assertThat(myList).hasSize(size)

Find/replace regex:

assertEquals\((.*),(.*).size\(\)\); -> assertThat(\2).hasSize(\1);

It’s better to run this before the assertEqualsisEqualTo conversion to avoid ending with assertThat(myList.size()).isEqualTo(expectedSize).

Converting assertEquals(expected, actual) to assertThat(actual).isEqualTo(expected)

Find/replace regex:

assertEquals\((.*),(.*)\); -> assertThat(\2).isEqualTo(\1);
Converting assertNull(objectUnderTest) to assertThat(objectUnderTest).isNull()

Find/replace regex:

assertNull\((.*)\); -> assertThat(\1).isNull();
Converting assertNotNull(objectUnderTest) to assertThat(objectUnderTest).isNotNull()

Find/replace regex:

assertNotNull\((.*)\); -> assertThat(\1).isNotNull();
Converting assertFalse(logicalCondition) to assertThat(logicalCondition).isFalse()

Find/replace regex:

assertFalse\((.*)\); -> assertThat(\1).isFalse();

2.8. AssertJ Sample Projects

The assertions-examples repository hosts executable AssertJ assertions examples that you can run as JUnit tests. Please have a look at assertions examples sources.

The main branch contains examples with the latest released version of AssertJ modules for Java 8, similarly the java-7 branch contains examples of AssertJ modules for Java 7. You should be able to build those two branches with mvn clean install command.

In your IDE, add src/test/generated-assertions to the project java test sources otherwise you will have errors/missing classes. This is the folder where custom assertions classes are generated by default by the maven assertions generator plugin. Note that Intellij Idea wrongly adds src/test/generated-assertions to the production sources when it should be added the test sources, you will have to fix that in your module/project settings.

Building the with-latest-snapshot-versions branch is a bit more complicated :

2.9. Release Notes

| | AssertJ Core would not exist without its contributors, you can find them all directly on GitHub. | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

The latest release notes can be found in the GitHub releases.

Older release notes:

2.9.1. AssertJ Core 3.23.0

Release date: 2022-05-31

Contributors

Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, BJ Hargrave, Jeremy Landis, Ashley Scopes, Roland Weisleder , Benedikt Bogason , Andreas Kutschera , Matthew , Chris HeZean , Leo0506 , Zhou Yicheng , Saria , Chunhao Liao , maxwell142857 , Jessica Hamilton , nith2001 , Arman Sharif , Yuta Saito , Minami Yoshihiko , Martin Witt , Wojciech Zankowski , Gatien Bovyn , Flora Zheng , Natalia Struharova , Sára Juhošová , Pawel , Diego Krupitza , Jiashu Zhang , YeeTone Wang , Yitong , Anugrah Singhal , Stefan Bratanov , and Almir James Lucena .

Binary compatibility

The release is binary compatible with the previous minor version. More details are available in the [[Binary Compatibility]](#Binary Compatibility) section.

New features

Improvements

Fixed

Deprecated

Add more assertThat…​Exception alternatives

Add more ThrowableTypeAssert entry point methods for commonly used exception:

This allow to check that piece of code expressed as a ThrowingCallable throws the proper exception type and chain additional assertions.

Example:

// succeeds
assertThatRuntimeException().isThrownBy(() -> {
  throw new RuntimeException("boom");
}).withMessage("boom");

// fails
assertThatRuntimeException().isThrownBy(() -> {
  throw new IOException();
})

Add linesOf variants to load a Path content

Loads the text content of a file at a given path into a list of strings with the given charset or the default charset if none is specified.

Each string corresponding to a line, the line endings are either \n, \r or \r\n.

Example:

// Terry-Pratchett.txt content:
// I'll be more enthusiastic about encouraging thinking outside the box ...
// ...when there's evidence of any thinking going on inside it.
Path pratchettQuotePath = Paths.get("Terry-Pratchett.txt");

assertThat(linesOf(pratchettQuotePath)).contains("I'll be more enthusiastic about encouraging thinking outside the box ...",
                                                 "...when there's evidence of any thinking going on inside it");

Add isStatic/isNotStatic class assertions

Add assertions to verify whether a class is static or not.

Example:

class MyClass {
  static class MyStaticClass {}
}

assertThat(MyClass.class).isNotStatic();
assertThat(MyStaticClass.class).isStatic();

Add containsIgnoringNewLines string assertion

Verifies that the {@code CharSequence} under test contains all the given values ignoring new line differences.

Example:

assertThat("Gandalf\nthe\ngrey").containsIgnoringNewLines("alf")
                                .containsIgnoringNewLines("alf", "grey")
                                .containsIgnoringNewLines("thegrey")
                                .containsIgnoringNewLines("thegr\ney")
                                .containsIgnoringNewLines("t\nh\ne\ng\nr\ney");

Add BigDecimal scale assertion

Returns an assert object that allows performing assertions on the scale of the BigDecimal under test.

Once this method is called, the object under test is no longer the BigDecimal but its scale. To go back performing assertions on the BigDecimal, call returnToBigDecimal().

Example:

assertThat(new BigDecimal("3.14")).scale()
                                    .isGreaterThan(1L)
                                    .isLessThan(5L)
                                  .returnToBigDecimal()
                                    .isPositive();

Add java.util.regex.Matcher assertions class with matches assertion

Verifies that the java.util.regex.Matcher matches.

Example:

Pattern pattern = Pattern.compile("a*");
Matcher matcher = pattern.matcher("aaa");
assertThat(matcher).matches();

Add hasNumberOfRows to two-dimensional array assertions

Verifies that the actual two-dimensional array has the given number of rows.

Example:

assertThat(new int[][] {{1, 2, 3}, {4, 5, 6}}).hasNumberOfRows(2);
assertThat(new long[][] {{1}, {1, 2}, {1, 2, 3}}).hasNumberOfRows(3);

Add hasYear, hasMonth, hasMonthValue and hasDayOfMonth LocalDate assertions

Verifies that actual LocalDate is in the given year, month/monthValue or day of month.

Example:

assertThat(LocalDate.of(2000, 12, 31)).hasYear(2000)
                                      .hasMonth(Month.DECEMBER)
                                      .hasMonthValue(12)
                                      .hasDayOfMonth(31);

Add hasHour, hasMinute, hasSecond and hasNano LocalTime assertions

Verifies that actual LocalTime is in the given hour, minute, second or nano.

Example:

assertThat(LocalTime.of(23, 17, 59, 05)).hasHour(23)
                                        .hasMinute(17)
                                        .hasSecond(59)
                                        .hasNano(05);

Add hasYear, hasMonth, hasMonthValue, hasDayOfMonth, hasHour, hasMinute, hasSecond and hasNano LocalDateTime assertions

Verifies that actual LocalDateTime is in the given year, month/monthValue, day of month, hour, minute, second or nano.

Example:

assertThat(LocalDateTime.of(2000, 12, 31, 23, 17, 59, 05)).hasYear(2000)
                                                         .hasMonth(Month.DECEMBER)
                                                         .hasMonthValue(12)
                                                         .hasDayOfMonth(31)
                                                         .hasHour(23)
                                                         .hasMinute(17)
                                                         .hasSecond(59)
                                                         .hasNano(05);

Add hasFileSystem and hasSameFileSystemAs Path assertions

Verifies that a path has the given file system or the same file system as another path

Examples:

Path jarFile = Paths.get("assertj-core.jar");
FileSystem mainFileSystem = jarFile.getFileSystem();

try (FileSystem fs = FileSystems.newFileSystem(jarFile, (ClassLoader) null)) {
  Path manifestFile = fs.getPath("META-INF", "MANIFEST.MF");

  assertThat(manifestFile).hasFileSystem(fs)
                          .hasSameFileSystemAs(jarFile);
}

Add binaryContent Path/File assertions

Returns ByteArray assertions on the content of the Path/File read.

Examples:

Path xFilePath = Files.write(Paths.get("xfile.txt"), "The Truth Is Out There".getBytes());
File xFile = xFilePath.toFile();

byte[] expectedBinaryContent = "The Truth Is Out There".getBytes()
assertThat(xFilePath).binaryContent().isEqualTo(expectedBinaryContent);
assertThat(xFile).binaryContent().isEqualTo(expectedBinaryContent);

Add ignoring case variants of startsWith, endsWith, doesNotStartWith, and doesNotEndWith CharSequence assertions

Add startsWithIgnoringCase, endsWithIgnoringCase, doesNotStartWithIgnoringCase and doesNotEndWithIgnoringCase to CharSequence assertions.

Examples:

assertThat("Gandalf the grey").startsWithIgnoringCase("gandalf")
                              .startsWithIgnoringCase("Gandalf")
                              .doesNotStartWithIgnoringCase("Saroumane")
                              .endsWithIgnoringCase("Grey")
                              .endsWithIgnoringCase("grey")
                              .doesNotEndWithIgnoringCase("great");

2.9.2. AssertJ Core 3.22.0

Release date: 2022-01-03

Contributors

Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Yusuke Mukai , Martin Tarjányi , Trang Nguyen , jbock , Annette0127, Zihan Xu , Ashley Scopes , Benjamin Ze’ev Tels , Ahmad Sadeed , temp-droid , Ilya Koshaleu , Spacca , Erik Pragt , and Jeremy Landis.

Binary compatibility

The release is not binary compatible with the previous minor version. More details are available in the [[Binary Compatibility]](#Binary Compatibility) section.

Breaking changes

New features

Improvements

Fixed

Deprecated

Deprecate encodedAsBase64 / decodedAsBase64 in favor of asBase64Encoded / asBase64Decoded

Add size assertions for File

Returns an Assert object that allows performing assertions on the size of the File under test.

Once this method is called, the object under test is no longer the File but its size, to return performing assertions on the File, call returnToFile().

Example:

File file = File.createTempFile("tmp", "bin");
Files.write(file.toPath(), new byte[] {1, 1});

assertThat(file).size()
                  .isGreaterThan(1L)
                  .isLessThan(5L)
                .returnToFile()
                  .hasBinaryContent(new byte[] {1, 1});

Add message() navigation method for Throwable

A shortcut for extracting(Throwable::getMessage, as(InstanceOfAssertFactories.STRING)) which allows to extract a throwable’s message and then execute assertions on it.

Note that once you have navigated to the throwable’s message you can’t navigate back to the throwable.

Example:

Throwable throwable = new Throwable("boom!");

assertThat(throwable).message().startsWith("boo")
                               .endsWith("!");

Add singleElement for Object[] assertions

Verifies that the array under test contains a single element and allows performing assertions on that element.

The assertions can be strongly typed if given an AssertFactory parameter.

Example:

String[] babySimpsons = { "Maggie" };

// object assertions
assertThat(babySimpsons).singleElement()
                        .isEqualTo("Maggie");

// strongly typed assertions with a predefined AssertFactory
import static org.assertj.core.api.Assertions.as; // syntactic sugar
import static org.assertj.core.api.InstanceOfAssertFactories.STRING;

assertThat(babySimpsons).singleElement(as(STRING))
                        .startsWith("Mag");

Add hasNoHost to URI and URL assertions

Verifies that the actual URI/URL has no host.

Example:

assertThat(new URI("file:///home/user/Documents/hello-world.txt")).hasNoHost();
assertThat(new URL("file:///home/user/Documents/hello-world.txt")).hasNoHost();

Add doesNotReturn to Object assertions

Verifies that the object under test does not return the given expected value from the given Function, a typical usage is to pass a method reference to assert object’s property.

Wrapping the given Function with Assertions.from(Function) makes the assertion more readable.

Example:

// from is not mandatory but it makes the assertions more readable
assertThat(frodo).doesNotReturn("Bilbo", from(TolkienCharacter::getName))
                 .doesNotReturn("Bilbo", TolkienCharacter::getName) // no from :(
                 .doesNotReturn(null, from(TolkienCharacter::getRace));

2.9.3. AssertJ Core 3.21.0

Release date: 2021-09-20

Contributors

Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Shivakumar Swamy, Iván Aguilar, Alberto Pascual, Gily H, Stefan Bischof, RGalways17, Andrey Kuzmin, Eugene Lesnov, Szymon Linowski, Julian Honnen, Almir James Lucena and Golan Levy.

Binary compatibility

The release is binary compatible with the previous minor version. More details are available in the [[Binary Compatibility]](#Binary Compatibility) section.

Breaking changes

New features

Improvements

Fixed

Add content()/content(Charset) to Path/File assertions to allow chaining string assertions on the Path/File content

Returns String assertions on the content of the actual Path/File read with the given charset or the default charset if no charset was given.

Example with content():

File xFile = Files.write(Paths.get("xfile.txt"), "The Truth Is Out There".getBytes()).toFile();

// assertion succeeds (default charset is used to read xFile content)
assertThat(xFile).content().startsWith("The Truth Is ")
                           .endsWith("There");
// assertion fails
assertThat(xFile).content().contains("Elsewhere");

Example with content(Charset):

File utf8File = Files.write(Paths.get("utf8.txt"), "é à".getBytes()).toFile();

// assertion succeeds
assertThat(utf8File).content(StandardCharsets.UTF_8).startsWith("é")
                                                    .endsWith("à");
// assertion fails
assertThat(utf8File).content(StandardCharsets.UTF_8).contains("e");

Add hasSize(long expectedSizeInBytes) to Path assertions

Asserts that the tested Path has the given size in bytes.

Note that the actual Path must exist and be a regular file.

Examples:

Path foxPath = Files.write(Paths.get("/fox.txt"), "The Quick Brown Fox.".getBytes());

// assertion succeeds
assertThat(foxPath).hasSize(20);

// assertion fails
assertThat(foxPath).hasSize(3);

Add isMixedCase() to CharSequence assertions

Verifies that the actual CharSequence is a mixed case CharSequence, i.e., neither uppercase nor lowercase.

If actual is empty or contains only case-independent characters, the assertion will pass.

Examples:

// assertions succeed
assertThat("Capitalized").isMixedCase();
assertThat("camelCase").isMixedCase();
assertThat("rAndOMcAse1234").isMixedCase();
assertThat("1@3$567").isMixedCase();
assertThat("").isMixedCase();

// assertions fail
assertThat("I AM GROOT!").isMixedCase();
assertThat("please be quiet").isMixedCase();

Add containsAnyOf(CharSequence…​ values) to CharSequence assertions

Verifies that the actual CharSequence contains any of the given values.

Examples:

// assertion succeeds
assertThat("Gandalf the grey").containsAnyOf("grey", "black");

// assertion fails
assertThat("Gandalf the grey").containsAnyOf("white", "black");

Add hasExtension(String extension) to Path assertions

Verifies that the actual Path has the given extension.

Examples:

Path path = Paths.get("file.java");

// assertion succeeds
assertThat(path).hasExtension("java");

// assertion fails
assertThat(path).hasExtension("png");

Add hasNoExtension() to Path and File assertions

Verifies that the actual Path or File has no extension.

Examples with Path:

// assertion succeeds
assertThat(Paths.get("file")).hasNoExtension();
assertThat(Paths.get("file.")).hasNoExtension();

// assertion fails
assertThat(Paths.get("file.txt")).hasNoExtension();

Add hasScaleOf(int expectedScale) to BigDecimals assertions

Verifies the BigDecimal under test has the given scale.

Examples:

// assertions succeed
assertThat(new BigDecimal("8.00")).hasScaleOf(2);
assertThat(new BigDecimal("8.00").setScale(4)).hasScaleOf(4);

// assertion fail
assertThat(new BigDecimal("8.00")).hasScaleOf(3);
assertThat(new BigDecimal("8.00").setScale(4)).hasScaleOf(2);

Add isUnmodifiable() to Collection assertions

Verifies that the actual collection is unmodifiable, i.e., throws an UnsupportedOperationException with any attempt to modify the collection.

Example:

// assertions succeed
assertThat(Collections.unmodifiableCollection(new ArrayList<>())).isUnmodifiable();
assertThat(Collections.unmodifiableList(new ArrayList<>())).isUnmodifiable();
assertThat(Collections.unmodifiableSet(new HashSet<>())).isUnmodifiable();

// assertions fail
assertThat(new ArrayList<>()).isUnmodifiable();
assertThat(new HashSet<>()).isUnmodifiable();

2.9.4. AssertJ Core 3.20.2

Release date: 2021-06-20

Bugfix release that revert a breaking change in 3.20.0 due to the heavy impact on binary compatibility and to continue allowing third-party libraries returning their own assertion classes with overridden assertThat methods.

Thanks to David Schlosnagle and Stefano Cordio for the fixes in this release.

Binary compatibility

The release is not binary compatible with the previous minor version. More details are available in the [[Binary Compatibility]](#Binary Compatibility) section.

Fixed

2.9.5. AssertJ Core 3.20.1

Release date: 2021-06-16

Bugfix release.

Binary compatibility

The release is not binary compatible with the previous minor version. More details are available in the [[Binary Compatibility]](#Binary Compatibility) section.

Fixed

2.9.6. AssertJ Core 3.20.0

Release date: 2021-06-15

Contributors

Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Harsha Vipparti, Julien Roy, Aakarshit Uppal, Abhijeet Shukla, Jack Gough, Filip Hrisafov, RGalways17, Stefan Birkner, Stefan Bischof, Matthieu Baechler, sustc11810424, Henry Coles, Annette0127, Johannes Becker, Slawomir Jaranowski, and Patrick Allain.

Special thanks to Filip Hrisafov to have got rid of the heap pollution compiler warning when using soft assertions or assumptions with methods having a generic vararg parameters.

Binary compatibility

The release is not binary compatible with the previous minor version. More details are available in the [[Binary Compatibility]](#Binary Compatibility) section.

Breaking changes

New features

Improvements

Fixed

Deprecated

The main deprecations are related to shallow field by field comparison classes and methods:

usingFieldByFieldElementComparator

Use usingRecursiveFieldByFieldElementComparator() or usingRecursiveComparison() instead to perform a true recursive comparison.

usingElementComparatorOnFields

Use usingRecursiveFieldByFieldElementComparatorOnFields(String…​) instead.

usingElementComparatorIgnoringFields

usingComparatorForElementFieldsWithNames

This method is used with usingFieldByFieldElementComparator() which is deprecated in favor of usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration) or usingRecursiveComparison().

When using usingRecursiveComparison() the equivalent is:

and when using usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration config), sets the config with:

usingComparatorForElementFieldsWithType

This method is used with usingFieldByFieldElementComparator() which is deprecated in favor of usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration) or usingRecursiveComparison().

When using usingRecursiveComparison() the equivalent is:

and when] using usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration config), sets the config with:

Add containsIgnoringWhitespaces to String assertions

Verifies that the actual CharSequence contains all the given values, ignoring whitespace differences.

Example:

assertThat("Gandalf the grey").containsIgnoringWhitespaces("alf")
                              .containsIgnoringWhitespaces("alf", "grey")
                              .containsIgnoringWhitespaces("thegrey")
                              .containsIgnoringWhitespaces("thegr  ey")
                              .containsIgnoringWhitespaces("t h e g r\t\r\n ey");

Add IterableAssert.elements(int…​) to assert on specific elements in an Iterable

Allow to perform assertions on the elements corresponding to the given indices (the iterable Iterable under test is changed to an iterable with the selected elements).

Example:

Iterable<TolkienCharacter> hobbits = Arrays.asList(frodo, sam, pippin);

// assertion succeeds
assertThat(hobbits).elements(1, 2)
                   .hasSize(2)
                   .containsExactly(sam, pippin);

// assertion fails
assertThat(hobbits).element(1, 2)
                   .containsExactly(frodo, pippin);

Add hasExactlyElementsOfTypes assertion for iterables, arrays and AtomicReferenceArrays

Verifies that the actual elements are of the given types in the given order, there should be as many expected types as there are actual elements.

This assertion is available for iterables, arrays and AtomicReferenceArrays.

Example:

Iterable<Object> list = Arrays.asList(1, "a", "b", 1.00);

assertThat(list).hasExactlyElementsOfTypes(Integer.class, String.class, String.class, Double.class);

Add asString(charset) to AbstractInputStreamAssert to support String assertions

Converts the content of the actual InputStream to a String by decoding its bytes using the given charset and returns assertions for the computed String allowing String specific assertions from this call.

Example:

InputStream abcInputStream = new ByteArrayInputStream("abc".getBytes());

assertThat(abcInputStream).asString(UTF_8)
                          .startsWith("a");

allOf condition error message shows state (successful/failed) of each combined conditions

allOf condition error message reports which conditions failed [✗] and which succeeded [✓] to ease understanding the failure cause.

Let’s use an allOf condition checking 3 conditions: young, very tall and Jedi and try it on Yoda, it fails with the following error:

Expecting actual:
  "Yoda"
to be:
[✗] all of:[
   [✓] a Jedi,
   [✗] very tall,
   [✗] young
]

Add assertWith assertion construct

Uses the given instance as the instance under test for all the assertions expressed as the passed Consumer.

This is useful to avoid repeating getting the instance to test, a bit like a with block which turns the target into the equivalent of this (as in Groovy for example).

Example:

assertWith(team.getPlayers().get(0).getStats(),
           stats -> {
              assertThat(stats.pointPerGame).isGreaterThan(25.7);
              assertThat(stats.assistsPerGame).isGreaterThan(7.2);
              assertThat(stats.reboundsPerGame).isBetween(9, 12);
           });

assertWith is variation of AbstractAssert.satisfies(Consumer) hopefully easier to find for some users.

Add isNotFinite float and double assertions

Verifies that the double/float value is not a finite floating-point value.

Note that 'not finite' is not equivalent to infinite as NaN is neither finite or infinite.

Examples:

assertThat(Double.POSITIVE_INFINITY).isNotFinite();
assertThat(Double.NEGATIVE_INFINITY).isNotFinite();
assertThat(Double.NaN).isNotFinite();

assertThat(Float.POSITIVE_INFINITY).isNotFinite();
assertThat(Float.NEGATIVE_INFINITY).isNotFinite();
assertThat(Float.NaN).isNotFinite();

Add isNotInfinite float and double assertions

Verifies that the double/float value represents neither positive infinity nor negative infinity.

Examples with doubles:

// assertions succeed
assertThat(1.0).isNotInfinite();
assertThat(Double.NaN).isNotInfinite();

// assertions fail
assertThat(Double.POSITIVE_INFINITY).isNotInfinite();
assertThat(Double.NEGATIVE_INFINITY).isNotInfinite();

Add comparingOnlyFields float and double assertions

Makes the recursive comparison to only compare given actual fields and their subfields (no other fields will be compared).

Specifying a field will make all its subfields to be compared, for example specifying person will lead to compare person.name, person.address and all other Person fields. On the other hand if you specify person.name, person won’t be compared but person.name will be.

The fields are specified by name, not by value, for example you can specify person.name but not "Jack" as "Jack" is not a field value.

comparingOnlyFields can be combined with ignoring fields methods to restrict further the fields actually compared, the resulting compared fields = {specified compared fields} - {specified ignored fields}. For example if compared fields = {"foo", "bar", "baz"} and ignored fields = {"bar"} then only {"foo", "baz"} fields will be compared.

Example:

public class Person {
  String name;
  double height;
  Home home = new Home();
}

public class Home {
  Address address = new Address();
}

public static class Address {
  int number;
  String street;
}

Person sherlock = new Person("Sherlock", 1.80);
sherlock.home.address.street = "Baker Street";
sherlock.home.address.number = 221;

Person moriarty = new Person("Moriarty", 1.80);
moriarty.home.address.street = "Butcher Street";
moriarty.home.address.number = 221;

// assertion succeeds as name and home.address.street fields are not compared.
assertThat(sherlock).usingRecursiveComparison()
                    .comparingOnlyFields("height", "home.address.number")
                    .isEqualTo(moriarty);

// assertion fails as home.address.street fields differ.
assertThat(sherlock).usingRecursiveComparison()
                    .comparingOnlyFields("height", "home")
                    .isEqualTo(moriarty);

Add usingRecursiveFieldByFieldElementComparatorOnFields(String…​) to iterable/array/atomic reference array assertions to restrict the recursive comparison to the specified fields

The assertions chained after this method will use a recursive field by field comparison on the given fields (including inherited fields) instead of relying on the element equals method. This is handy when the element equals method is not overridden or implemented as you expect.

Nested fields are supported and are expressed like: name.first

The comparison is recursive: elements are compared field by field, if a field type has fields they are also compared field by field (and so on).

Example:

Player derrickRose = new Player(new Name("Derrick", "Rose"), "Chicago Bulls");
derrickRose.nickname = new Name("Crazy", "Dunks");

Player jalenRose = new Player(new Name("Jalen", "Rose"), "Chicago Bulls");
jalenRose.nickname = new Name("Crazy", "Defense");

// assertion succeeds as all compared fields match
assertThat(list(derrickRose)).usingRecursiveFieldByFieldElementComparatorOnFields("name.last", "team", "nickname.first")
                             .contains(jalenRose);

// assertion fails, name.first values differ
assertThat(list(derrickRose)).usingRecursiveFieldByFieldElementComparatorOnFields("name")
                             .contains(jalenRose);

This method is actually a shortcut of usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration) with a configuration comparing only the given fields, the previous example can be written as:

RecursiveComparisonConfiguration configuration = RecursiveComparisonConfiguration.builder()
                                                                                 .withComparedFields("name.last", "team", "nickname.first")
                                                                                 .build();

assertThat(list(derrickRose)).usingRecursiveFieldByFieldElementComparator(configuration)
                             .contains(jalenRose);

Add usingRecursiveFieldByFieldElementComparatorIgnoringFields(String…​) to iterable/array/atomic reference array assertions to ignore some fields in the recursive comparison

The assertions chained after this method will use a recursive field by field comparison on all fields (including inherited fields) except the given ones instead of relying on the element equals method. This is handy when the element equals method is not overridden or implemented as you expect.

Nested fields are supported and are expressed like: name.first

The comparison is recursive: elements are compared field by field, if a field type has fields they are also compared field by field (and so on).

Example:

Player derrickRose = new Player(new Name("Derrick", "Rose"), "Chicago Bulls");
derrickRose.nickname = new Name("Crazy", "Dunks");

Player jalenRose = new Player(new Name("Jalen", "Rose"), "Chicago Bulls");
jalenRose.nickname = new Name("Crazy", "Defense");

// assertion succeeds as all compared fields match
assertThat(list(derrickRose)).usingRecursiveFieldByFieldElementComparatorIgnoringFields("name.last", "nickname.first")
                             .contains(jalenRose);

// assertion fails, names are ignored but nicknames are not and nickname.last values differ
assertThat(list(derrickRose)).usingRecursiveFieldByFieldElementComparatorIgnoringFields("name")
                             .contains(jalenRose);

This method is actually a shortcut of usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration) with a configuration comparing only the given fields, the previous example can be written as:

RecursiveComparisonConfiguration configuration = RecursiveComparisonConfiguration.builder()
                                                                                 .withIgnoredFields("name.first", "nickname.last")
                                                                                 .build();

assertThat(list(derrickRose)).usingRecursiveFieldByFieldElementComparator(configuration)
                             .contains(jalenRose);

Add MappedCondition to verify a Condition on the result of a map operation

A MappedCondition is defined with a map operation and a Condition that accepts the type returned by the map operation.
When applied the MappedCondition first map the value under test and then verify the resulting mapped value against its nested Condition.

Let’s see how it works on an example:

// nested Condition
Condition<String> hasLineSeparator = new Condition<>(s -> s.contains(System.lineSeparator()), "has lineSeparator");
// mapped Condition
Condition<Optional<String>> optionalWithLineSeparator = MappedCondition.mappedCondition(Optional::get, hasLineSeparator, "optional value has lineSeparator");

// assertion succeeds
assertThat(Optional.of("a" + System.lineSeparator())).is(optionalWithLineSeparator)

// assertion fails
assertThat(Optional.of("a")).is(optionalWithLineSeparator)

Add VerboseCondition to get a detailed description when the condition fails

A VerboseCondition shows the value under test when it fails thanks to the specified objectUnderTestDescriptor function.

When defining the objectUnderTestDescriptor function, you should take in consideration whether the condition is going to be used with is(Condition) or has(Condition) since the start of the error message is different between the two.

Let’s see how it works with an example that works well with is(Condition):

Condition<String> shorterThan4 = VerboseCondition.verboseCondition(actual -> actual.length() < 4,
                                                                   // predicate description
                                                                   "shorter than 4",
                                                                   // value under test description transformation function
                                                                   s -> String.format(" but length was %s", s.length()));

If we execute:

assertThat("foooo").is(shorterThan4);

we get the following assertion error:

Expecting actual:
  "foooo"
to be shorter than 4 but length was 5

Note that the beginning of the error message looks nice with is(Condition) but not so much has(Condition):

Expecting actual:
  "foooo"
to have shorter than 4 but length was 5

2.9.7. AssertJ Core 3.19.0

Release date: 2021-01-24

Contributors

Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Pascal Schumacher, Arsen Ibragimov, Kim S. Ly, Victor Wang, Omar Morales, Reto Weiss, Michael Florian Grafl, Sergei Tachenov, Mayra Lucero Garcia Ramírez, Eveneko, Julieta Navarro, Michael Keppler, Alex Dukhno, Himadri Mandal and Jin Kwon.

Binary compatibility

The release is not binary compatible with the previous minor version. More details are available in the [[Binary Compatibility]](#Binary Compatibility) section.

Breaking changes

New features

Improvements

expected: "abc"
but was : "bcd"

Fixed

Deprecated

Add isEqualToNormalizingUnicode CharSequence assertion

Verifies that the actual CharSequence is equal to the given one after they have been normalized according to the Normalizer.Form.NFC form, which is a canonical decomposition followed by canonical composition.

Examples:

// assertions succeed:

// Ä = \u00C4 - Ä = \u0041\u0308
assertThat("Ä").isEqualToNormalizingUnicode("Ä");
assertThat("\u00C4").isEqualToNormalizingUnicode("\u0041\u0308");

// assertions fail:
assertThat("ñ").isEqualToNormalizingUnicode("n");
assertThat("Ä").isEqualToNormalizingUnicode("b");

Add satisfiesExactly iterable/array assertion

Verifies that each element satisfies the requirements corresponding to its index, so the first element must satisfy the first requirements, the second element the second requirements etc…​

Each requirement is expressed as a Consumer, and there must be as many requirements as there are iterable elements.

Examples:

Iterable<TolkienCharater> characters = list(frodo, aragorn, legolas);

// assertions succeed
assertThat(characters).satisfiesExactly(character -> assertThat(character.getRace()).isEqualTo("Hobbit"),
                                        character -> assertThat(character.isMortal()).isTrue(),
                                        character -> assertThat(character.getName()).isEqualTo("Legolas"));

// you can specify more that one assertion per requirements
assertThat(characters).satisfiesExactly(character -> {
                                           assertThat(character.getRace()).isEqualTo("Hobbit");
                                           assertThat(character.getName()).isEqualTo("Frodo");
                                        },
                                        character -> {
                                           assertThat(character.isMortal()).isTrue();
                                           assertThat(character.getName()).isEqualTo("Aragorn");
                                        },
                                        character -> {
                                           assertThat(character.getRace()).isEqualTo("Elf");
                                           assertThat(character.getName()).isEqualTo("Legolas");
                                        });

// assertion fails as aragorn does not meet the second requirements
assertThat(characters).satisfiesExactly(character -> assertThat(character.getRace()).isEqualTo("Hobbit"),
                                        character -> assertThat(character.isMortal()).isFalse(),
                                        character -> assertThat(character.getName()).isEqualTo("Legolas"));

Add satisfiesExactlyInAnyOrder iterable/array assertion

Verifies that at least one combination of iterable elements exists that satisfies the consumers in order (there must be as many consumers as iterable elements and once a consumer is matched it cannot be reused to match other elements).

This is a variation of satisfiesExactly where order does not matter.

Examples:

List<String> starWarsCharacterNames = list("Luke", "Leia", "Yoda");

// these assertions succeed:
assertThat(starWarsCharacterNames).satisfiesExactlyInAnyOrder(name -> assertThat(name).contains("Y"), // matches "Yoda"
                                                              name -> assertThat(name).contains("L"), // matches "Luke" and "Leia"
                                                              name -> {
                                                                assertThat(name).hasSize(4);
                                                                assertThat(name).doesNotContain("a"); // matches "Luke" but not "Leia"
                                                              })
                                  // satisfiesExactly would have succeeded for this assertion
                                  .satisfiesExactlyInAnyOrder(name -> assertThat(name).contains("Lu"),
                                                              name -> assertThat(name).contains("Le"),
                                                              name -> assertThat(name).contains("Yo"))
                                  // satisfiesExactly would have failed for this assertion
                                  .satisfiesExactlyInAnyOrder(name -> assertThat(name).contains("Yo"),
                                                              name -> assertThat(name).contains("Lu"),
                                                              name -> assertThat(name).contains("Le"))
                                  // satisfiesExactly would have failed for this assertion
                                  .satisfiesExactlyInAnyOrder(name -> assertThat(name).contains("Le"),
                                                              name -> assertThat(name).contains("Yo"),
                                                              name -> assertThat(name).contains("Lu"));

// this assertion fails as 3 consumer/requirements are expected
assertThat(starWarsCharacterNames).satisfiesExactlyInAnyOrder(name -> assertThat(name).contains("Y"),
                                                              name -> assertThat(name).contains("L"));

// this assertion fails as no element contains "Han" (first consumer/requirements can't be met)
assertThat(starWarsCharacterNames).satisfiesExactlyInAnyOrder(name -> assertThat(name).contains("Han"),
                                                              name -> assertThat(name).contains("L"),
                                                              name -> assertThat(name).contains("Y"));

// this assertion fails as "Yoda" element can't satisfy any consumers/requirements (even though all consumers/requirements are met)
assertThat(starWarsCharacterNames).satisfiesExactlyInAnyOrder(name -> assertThat(name).contains("L"),
                                                              name -> assertThat(name).contains("L"),
                                                              name -> assertThat(name).contains("L"));

// this assertion fails as no combination of elements can satisfy the consumers in order
// the problem is if the last consumer is matched by Leia then no other consumer can match Luke (and vice versa)
assertThat(starWarsCharacterNames).satisfiesExactlyInAnyOrder(name -> assertThat(name).contains("Y"),
                                                              name -> assertThat(name).contains("o"),
                                                              name -> assertThat(name).contains("L"));

Add Instant variants to Date assertions

Date assertions now understand Instant parameters.

Examples:

final Date dateTimeWithMs = parseDatetimeWithMs("2001-02-03T04:05:06.700");

assertThat(dateTimeWithMs).isEqualTo(dateTimeWithMs.toInstant())
                          .isBefore(Instant.parse("2002-01-01T00:00:00.00Z"))
                          .isAfter(Instant.parse("2000-01-01T00:00:00.00Z"))
                          .isBetween(Instant.parse("2000-01-01T00:00:00.00Z"),
                                     Instant.parse("2002-01-01T00:00:00.00Z"))
                          .isCloseTo(dateTimeWithMs.toInstant().minusMillis(10), 20)
                          .isEqualToIgnoringHours(dateTimeWithMs.toInstant().plus(1, ChronoUnit.HOURS))
                          .isEqualToIgnoringMinutes(dateTimeWithMs.toInstant().plus(1, ChronoUnit.MINUTES))
                          .isEqualToIgnoringSeconds(dateTimeWithMs.toInstant().plus(1, ChronoUnit.SECONDS))
                          .isEqualToIgnoringMillis(dateTimeWithMs.toInstant().plus(1, ChronoUnit.MILLIS))
                          .isIn(dateTimeWithMs.toInstant(), dateTimeWithMs.toInstant().plusMillis(10))
                          .isInSameDayAs(dateTimeWithMs.toInstant().plus(1, ChronoUnit.MINUTES))
                          .isInSameMonthAs(Instant.parse("2001-02-01T00:00:00.00Z"))
                          .isInSameYearAs(Instant.parse("2001-01-01T00:00:00.00Z"))
                          .isNotIn(dateTimeWithMs.toInstant().minusMillis(10), dateTimeWithMs.toInstant().plusMillis(10));

Add float/double finite or infinite assertions

Examples:

assertThat(1.0f).isFinite();
assertThat(Float.NEGATIVE_INFINITY).isInfinite();

assertThat(1.0).isFinite();
assertThat(Double.POSITIVE_INFINITY).isInfinite();

Add doesNotHaveSameHashCodeAs assertion

Verifies that the actual object does not have the same hashCode as the given object.

Examples:

// assertions succeed
assertThat(42L).doesNotHaveSameHashCodeAs(2501L);
assertThat("The Force").doesNotHaveSameHashCodeAs("Awakens");

// assertions fail
assertThat(42L).doesNotHaveSameHashCodeAs(42L);
assertThat("The Force").doesNotHaveSameHashCodeAs("The Force");
assertThat(new Jedi("Yoda", "Blue")).doesNotHaveSameHashCodeAs(new Jedi("Yoda", "Blue"));

Add doesNotHaveToString assertion

Verifies that the actual object does not have the same toString as the given object.

Examples:

CartoonCharacter homer = new CartoonCharacter("Homer");

// Instead of writing ...
assertThat(homer.toString()).isNotEqualTo("Marge");
// ... you can simply write:
assertThat(homer).doesNotHaveToString("Marge");

Add overloaded contains assertions with boxed arrays for primitive array assertions

Primitive array assertions (like long[] assertions) support variants with boxed arrays (e.g. Long[]) for contains assertions.

Examples:

assertThat(new boolean[] { true, false, true }).containsExactly(new Boolean[] {true, false, true });
assertThat(new short[] { 1,  2,  3 }).containsExactly(new Short[] { 1,  2,  3 });
assertThat(new int[] { 1,  2,  3 }).containsExactly(new Integer[] { 1,  2,  3 });
assertThat(new long[] { 1L, 2L, 3L }).contains(new Long[] { 1L, 2L });
assertThat(new float[] { 1.0f, 2.0f, 3.0f }).containsExactly(new Float[] { 1.0f, 2.0f, 3.0f });
assertThat(new double[] { 1.0, 2.0, 3.0 }).containsExactly(new Double[] { 1.0, 1.98, 3.01 }, withPrecision(0.05));
assertThat(new char[] { 'a', 'b', 'c' }).contains(new Character[] { 'a', 'b' });

Add hasOnlyFields assertion

Verifies that the actual object has only the specified fields and nothing else.

The assertion only checks declared fields (inherited fields are not checked) that are not static or synthetic.

Examples:

public class TolkienCharacter {

  private String name;
  public int age;

  public String getName() {
    return this.name;
  }
}

TolkienCharacter frodo = new TolkienCharacter("Frodo", 33);

// assertion succeeds:
assertThat(frodo).hasOnlyFields("name", "age");

// assertions fail:
assertThat(frodo).hasOnlyFields("name");
assertThat(frodo).hasOnlyFields("not_exists");

Allow to pass a lazy description only evaluated when the assertion fails

Lazily specifies the description of the assertion that is going to be called, the given description is not evaluated if the assertion succeeds. This is useful if descriptions are expansive to build.

Examples:

// we all know Mr Frodo is 33 years old
frodo.setAge(33);

// the lazy test description is not evaluated as the assertion succeeds
assertThat(frodo.getAge()).as(() -> "check Frodo's age").isEqualTo(33);

// the lazy test description is evaluated as the assertion fails
assertThat(frodo.getAge()).as(() -> "check Frodo's age").isEqualTo(50);

The error message of the failing assertion is:

[check Frodo's age]
expected: 33
but was : 50

Add isEmptyFile and isNotEmptyFile to Path assertions

Verify that the actual Path is respectively an empty or non empty regular file.

Note that the actual Path must exist and be a regular file.

Examples given the files below:

/root/sub-dir-1/file-1.ext (no content)
/root/sub-dir-1/file-2.ext (content)

Here are some assertions examples:

Path withoutContent = Paths.get("/root/sub-dir-1/file-1.ext");
Path withContent = Paths.get("/root/sub-dir-1/file-2.ext");

// The following assertions succeed:
assertThat(withoutContent).isEmptyFile();
assertThat(withContent).isNotEmptyFile();

// The following assertions fail:
assertThat(withoutContent).isNotEmptyFile();
assertThat(withContent).isEmptyFile();

2.9.8. AssertJ Core 3.18.1

Release date: 2020-11-11

Contributors

Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio and Kim S. Ly.

Binary compatibility

The release is not binary compatible with the previous minor version. More details are available in the [[Binary Compatibility]](#Binary Compatibility) section.

New features

Improvements

Fixed

2.9.9. AssertJ Core 3.18.0

Release date: 2020-10-25

Contributors

Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Pascal Schumacher, Fr Jeremy Krieg, BJ Hargrave, Matteo Mirk and Valeriy Vyrva.

Shout out to Fr Jeremy Krieg for adding soft assertions field injection capability in JUnit 5 SoftAssertionsExtension!

Binary compatibility

The release is not binary compatible with the previous minor version. More details are available in the [[Binary Compatibility]](#Binary Compatibility) section.

Breaking changes

New features

Improvements

Fixed

Deprecated

// deprecated
assertThat(future).hasFailed();
// instead calls
assertThat(future).isCompletedExceptionally()
                  .isNotCancelled();
// deprecated
CompletableFuture future = new CompletableFuture();
future.completeExceptionally(new RuntimeException("boom!"));

assertThat(future).hasFailedWithThrowableThat().isInstanceOf(RuntimeException.class);
                                               .hasMessage("boom!");
// instead calls
assertThat(future).failsWithin(1, TimeUnit.SECONDS)
                  .withThrowableOfType(RuntimeException.class)
                  .withMessage("boom!");

Please note that the semantics of a failure in failsWithin differs from hasFailedWithThrowableThat, failsWithin tries to get the future after the given duration and return the exception that led to its failure while hasFailedWithThrowableThat checks the future is completed exceptionnaly and was not cancelled.

CompletableFuture future = new CompletableFuture();
future.cancel(true);
// deprecated
assertThat(future).hasNotFailed();
// instead calls
assertThat(future).matches (f -> f.isNotCompletedExceptionally() || f.isCancelled());

Add hasPackage to Class assertions

Verifies that the actual Class under test has the given package name.

Example:

package one.two;

class MyClass {}

assertThat(MyClass.class).hasPackage("one.two")
                         .hasPackage(Package.getPackage("one.two"));

Add isCloseTo to java.time.Duration assertions

Verifies that the actual Duration is close to the given one within the given allowed difference (assertion succeeds if difference = allowed difference).

This is equivalent of: abs(actual - expected) ≤ allowed difference.

For readability, Assertions.withMarginOf(Duration) can be used to express the allowed difference.

Examples:

Duration twoMinutes = Duration.ofMinutes(2);

assertThat(twoMinutes).isCloseTo(Duration.ofMinutes(3), Duration.ofMinutes(5));
assertThat(twoMinutes).isCloseTo(Duration.ofMinutes(-3), Duration.ofMinutes(10));
assertThat(twoMinutes).isCloseTo(Duration.ofMinutes(3), Duration.ofMinutes(1));

// assertions using withMarginOf syntactic sugar
assertThat(twoMinutes).isCloseTo(Duration.ofMinutes(3), withMarginOf(Duration.ofMinutes(5)));
assertThat(twoMinutes).isCloseTo(Duration.ofMinutes(3), withMarginOf(Duration.ofMinutes(1)));

Add failsWithin to Future and CompletableFuture assertionss

Checks that the Future/CompletableFuture does not complete within the given time and returns the exception that caused the failure for further (exception) assertions, the exception can be any of InterruptedException, ExecutionException, TimeoutException or CancellationException as per Future.get(long, TimeUnit) behaviour.

WARNING

failsWithin does not fully integrate with soft assertions, if the future completes the test will fail immediately (the error is not collected as a soft assertion error), if the assertion succeeds the chained assertions are executed and any errors will be collected as a soft assertion errors. The rationale is that if we collect failsWithin error as a soft assertion error, the chained assertions would be executed but that does not make sense since there is no exception to check as the future has completed.

Examples:

ExecutorService executorService = Executors.newSingleThreadExecutor();

Future<String> future = executorService.submit(() -> {
  Thread.sleep(100);
  return "ook!";
});

// assertion succeeds as the future is not completed after 50ms
assertThat(future).failsWithin(Duration.ofMillis(10))
                  .withThrowableOfType(TimeoutException.class);

// alternative assertion syntax, the time out is expressed with a TimeUnit value
assertThat(future).failsWithin(10, TimeUnit.MILLISECONDS);


// fails as the future is completed within 200ms
assertThat(future).failsWithin(Duration.ofMillis(200));

Improve isTrue/isFalse assertions error messages

Before:

Expecting:
 <false>
to be equal to:
 <true>
but was not.

After:

Expecting value to be true but was false

Add hasValueSatisfying to AtomicReference assertions

Verifies that the atomic under test has a value satisfying the given predicate.

Examples:

assertThat(new AtomicReference("foo")).hasValueMatching(result -> result != null);

// you can pass a description for the predicate that will be used in the error message
assertThat(new AtomicReference("foo")).hasValueMatching(result -> result != null, "expected not null");

Add hasValueSatisfying to AtomicReference assertions

Verifies that the atomic under test has a value satisfying the given requirements.

Example:

assertThat(new AtomicReference("foo")).hasValueSatisfying(result -> assertThat(result).isNotBlank());

2.9.10. AssertJ Core 3.17.2

Release date: 2020-09-06

Contributors

Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio and BJ Hargrave.

Binary compatibility

The release is not binary compatible with the previous minor version. More details are available in the [[Binary Compatibility]](#Binary Compatibility) section.

Breaking changes

Improvements

Fixed

2.9.11. AssertJ Core 3.17.1

Release date: 2020-08-30

Contributors

Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Pascal Schumacher, rpolton, Andrey Nudko and Davide Angelocola.

Binary compatibility

The release is not binary compatible with the previous minor version. More details are available in the [[Binary Compatibility]](#Binary Compatibility) section.

Breaking changes

Improvements

Fixed

2.9.12. AssertJ Core 3.17.0

Release date: 2020-08-23

Contributors

Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Pascal Schumacher, Junhao Liang, Bibibiu, Andrey "Bass" Shcheglov, SuntCrick, Yubin Hu, rpolton, Ting Sun, Peng Weiyuan, Brummolix, Maciej Wajcht, Hayden Meloche, Cal027, sullis, mgrafl, Rupert Madden-Abbott, Shiva, Ahmad M, Phillip Webb and BJ Hargrave.

Joel Costigliola: Apologies to Hayden Meloche, when integrating his work the final squashed commit was pushed with me as the author instead of him, sorry Hayden!

Binary compatibility

The release is not binary compatible with the previous minor version. More details are available in the [[Binary Compatibility]](#Binary Compatibility) section.

Breaking changes

New features

Improvements

Fixed

Deprecated

Add java.time.Period assertions

Provides the following assertions for the Period:

Examples:

assertThat(Period.ofYears(5)).hasYears(5);

assertThat(Period.ofMonths(5)).hasMonths(5);

assertThat(Period.ofDays(5)).hasDays(5)
                            .isPositive();

assertThat(Period.ofMonths(-5)).isNegative();

Display the beginning and the end of huge iterables/array/map

Before this version only the first maxElementsForPrinting elements would be displayed, now the maxElementsForPrinting displayed elements are split between first and last elements.

The number of elements to display can be set with Assertions.setMaxElementsForPrinting(n);

Example:

// 6 elements array
String[] greatBooks = {"A Game of Thrones", "The Lord of the Rings", "Assassin's Apprentice",
                       "Guards! Guards!", "The Lies of Locke Lamora", "Aux Ombres d’Abyme"};

// limit the number of elements to display/print to 4
Assertions.setMaxElementsForPrinting(4);

// formatted as:
["A Game of Thrones", "The Lord of the Rings", ... "The Lies of Locke Lamora", "Aux Ombres d’Abyme"]

Add isEmpty to InputStream assertion

Verifies whether the content of the actual InputStream is empty.

Examples:

// assertion will pass
assertThat(new ByteArrayInputStream(new byte[] {})).isEmpty());

// assertions will fail
assertThat(new ByteArrayInputStream(new byte[] {0xa})).isEmpty();

Add isNotEmpty to InputStream assertion

Verifies that the content of the actual InputStream is not empty.

Examples:

// assertion will pass
assertThat(new ByteArrayInputStream(new byte[] {0xa})).isNotEmpty());

// assertions will fail
assertThat(new ByteArrayInputStream(new byte[] {})).isNotEmpty();

Add doesNotContainIgnoringCase to CharSequence assertions

Verifies that the actual CharSequence does not contain any of the given values, ignoring case considerations.

Example:

// assertions will pass
assertThat("Frodo").doesNotContainIgnoringCase("pippin")
                   .doesNotContainIgnoringCase("Merry", "sam");

// assertions will fail
assertThat("Frodo").doesNotContainIgnoringCase("Fro", "Gimli", "Legolas");
assertThat("Frodo").doesNotContainIgnoringCase("fro");

primitive and Object 2D array assertions

The following assertions are available 2D arrays, here they are for int[][]:

The same assertions are available for long[][], short[][], byte[][], float[][], double[][], boolean[][] and Object[][] (obviously replacing int by the array type).

Object[][] assertions are generic, they take a parameter type, ex: isDeepEqualTo(ELEMENT[][] expected).

The migration path from one-dimensional array assertions is the following:

Before 3.17.0 After 3.17.0
contains(ELEMENT, Index) contains(ELEMENT[], Index)
doesNotContain(ELEMENT, Index) doesNotContain(ELEMENT[], Index)
hasSameSizeAs(Iterable) hasSameDimensionsAs(Object)
hasSize(int) hasDimensions(int, int)
isEmpty() isEmpty()
isEqualTo(Object) isEqualTo(Object)
isNotEmpty() isNotEmpty()
isNullOrEmpty() isNullOrEmpty()

The remaining one-dimensional array assertions do not have a direct replacement. Please raise a feature request if there is any use case for them.

Add isEven/isOdd assertions for byte, short, int and long

Verifies whether the given byte, short, int and or long is even/odd.

Examples:

assertThat(12).isEven();
assertThat(-46).isEven();

assertThat(3).isOdd();
assertThat(-17).isOdd();

Add singleElement to iterable assertions

singleElement() and singleElement(InstanceOfAssertFactory assertFactory) verify that the Iterable under test contains a single element and allow to perform assertions on that element (this is a shorthand for hasSize(1).first()).

You can only chain Object assertions after singleElement(), to get strongly typed assertions, use singleElement(InstanceOfAssertFactory) and pass the proper InstanceOfAssertFactory.

Examples:

import static org.assertj.core.api.InstanceOfAssertFactories.STRING;
import static org.assertj.core.api.Assertions.as; // syntactic sugar

List<String> babySimpsons = list("Maggie");

// assertion succeeds, only Object assertions are available after singleElement()
assertThat(babySimpsons).singleElement()
                        .isEqualTo("Maggie");

// String assertion succeeds, String assertions as we have passed InstanceOfAssertFactories.STRING
assertThat(babySimpsons).singleElement(as(STRING))
                        .startsWith("Mag");

Add succeedsWithin to Future and CompletableFuture assertions

succeedsWithin waits if necessary for at most the given time for this future to complete and then returns its result for further assertions.

If the future’s result is not available for any reason an assertion error is thrown.

To get assertions for the future result’s type use the method taking an additionnal InstanceOfAssertFactory parameter instead.

Examples:

ExecutorService executorService = Executors.newSingleThreadExecutor();

Future<String> future = executorService.submit(() -> {
  Thread.sleep(100);
  return "ook!";
});

// assertion succeeds
assertThat(future).succeedsWithin(200, TimeUnit.MILLISECONDS)
                  .isEqualTo("ook!");

// same assertion with a Duration to express the time out
Duration timeout = Duration.ofMillis(200);
assertThat(future).succeedsWithin(timeout)
                  .isEqualTo("ook!");

// fails as the future is not done after the given timeout
assertThat(future).succeedsWithin(50, TimeUnit.MILLISECONDS);

Examples with stronly typed assertions and CompletableFuture:

import static org.assertj.core.api.InstanceOfAssertFactories.STRING;
import static org.assertj.core.api.Assertions.as; // syntactic sugar

CompletableFuture<String> future = CompletableFuture.completedFuture("ook!");

Duration timeout = Duration.ofMillis(200);

// strongly typed assertion:
assertThat(future).succeedsWithin(timeout, as(STRING))
                  .contains("ok");

// same assertion with the timeout expressed differently:
assertThat(future).succeedsWithin(200, TimeUnit.MILLISECONDS, as(STRING))
                  .contains("ok");

Add filteredOn(Function, expectedValue) to Iterable, Object[] and AtomicReferenceArray assertions

Filters the iterable under test keeping only elements for which the result of the function is equal to expectedValue.

It allows to filter elements more safely than by using filteredOn(String, Object) as it doesn’t utilize introspection.

As an example, let’s check all employees 800 years old (yes, special employees): Examples:

Employee yoda   = new Employee(1L, new Name("Yoda"), 800);
Employee obiwan = new Employee(2L, new Name("Obiwan"), 800);
Employee luke   = new Employee(3L, new Name("Luke", "Skywalker"), 26);
Employee noname = new Employee(4L, null, 50);

List<Employee> employees = newArrayList(yoda, luke, obiwan, noname);

assertThat(employees).filteredOn(Employee::getAge, 800)
                     .containsOnly(yoda, obiwan);

assertThat(employees).filteredOn(e -> e.getName(), null)
                     .containsOnly(noname);

2.9.13. AssertJ Core 3.16.1

Release date: 2020-05-09

Contributors

Thanks to Erhard Pointl and Eddú Meléndez Gonzales for their contributions.

Fixed

2.9.14. AssertJ Core 3.16.0

Release date: 2020-05-05

Contributors

Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Pascal Schumacher, Wim Deblauwe, Fabien Duminy, Piotrek Żygieło, Indrek Priks, Jakzi666, Daniel Avila, Harisha Talanki, Grzegorz Piwowarek, Andreas Mager, Sunt-ing, ebundy, Stefan Birkner, WuYff, Cal027, Yubin Hu and Fr Jeremy Krieg.

Breaking changes

New features

Improvements

Fixed

Deprecated

Add java.util.concurrent.atomic.LongAdder assertions

The following java.util.concurrent.atomic.LongAdder assertions are available:

Comparison ignoring punctuation and normalizing whitespaces

Verifies that the actual CharSequence is equal to the given one, after the punctuation of both strings have been normalized.

To be exact, the following rules are applied:

Examples:

// assertions succeed:
assertThat("Game'of'Thrones").isEqualToNormalizingPunctuationAndWhitespace("GameofThrones")
assertThat("Game of Throne's").isEqualToNormalizingPunctuationAndWhitespace("Game of Thrones")
assertThat(":Game of Thrones:").isEqualToNormalizingPunctuationAndWhitespace("Game of Thrones")
assertThat(":Game-of-Thrones:").isEqualToNormalizingPunctuationAndWhitespace("Game of Thrones")
assertThat("Game of Thrones?").isEqualToNormalizingPunctuationAndWhitespace("Game of Thrones")
assertThat("Game of Thrones!!!").isEqualToNormalizingPunctuationAndWhitespace("Game of Thrones")
assertThat("Game of  {{(!)}}    Thrones!!!").isEqualToNormalizingPunctuationAndWhitespace("Game of Thrones")
assertThat("{(Game)-(of)-(Thrones)!!!}").isEqualToNormalizingPunctuationAndWhitespace("GameofThrones");

// assertions fail:
assertThat("Game-of-Thrones").isEqualToNormalizingPunctuationAndWhitespace("Game of Thrones");
assertThat("{Game:of:Thrones}").isEqualToNormalizingPunctuationAndWhitespace("Game of Thrones");
assertThat("{(Game)-(of)-(Thrones)!!!}").isEqualToNormalizingPunctuationAndWhitespace("Game of Thrones");

isBase64

Verifies that the given String is a valid Base64 encoded string. (this is not available for CharSequence).

Examples:

// assertions succeeds
assertThat("QXNzZXJ0Sg==").isBase64();

// assertion succeeds even without padding as it is optional by specification
assertThat("QXNzZXJ0Sg").isBase64();

// assertion fails as it has invalid Base64 characters
assertThat("inv@lid").isBase64();

decodedAsBase64

Decodes the actual String value as a Base64 encoded string, the decoded bytes becoming the new array under test.

Examples:

// assertions succeeds
assertThat("QXNzZXJ0Sg==").decodedAsBase64()
                          .containsExactly("AssertJ".getBytes());

// assertion succeeds even without padding as it is optional by specification
assertThat("QXNzZXJ0Sg").decodedAsBase64()
                        .containsExactly("AssertJ".getBytes());

// assertion fails as it has invalid Base64 characters
assertThat("inv@lid").decodedAsBase64();

Add asHexString to byte[] assertions

Converts the actual byte array under test to an hexadecimal String and returns assertions for the computed String allowing String specific assertions from this call.
The hexadecimal String representation is in upper case.

Example :

byte[] bytes = new byte[] { -1, 0, 1 };

// assertion will pass
assertThat(bytes).asHexString()
                 .startsWith("FF")
                 .isEqualTo("FF0001");

Add isEqualToWithSortedQueryParameters] to URL assertions

Verifies that the actual URL is equivalent to the given one after their parameters are sorted.

Example :

URL url = new URL("http://example.com?a=b&c=d");

// these assertions succeed ...
assertThat(url).isEqualToWithSortedQueryParameters(new URL("http://example.com?c=d&a=b"))
               .isEqualToWithSortedQueryParameters(new URL("http://example.com?a=b&c=d"));

// ... but this one fails as parameters do not match.
assertThat(url).isEqualToWithSortedQueryParameters(new URL("http://example.com?a=b&c=e"));

//... and this one fails as domains are different.
assertThat(url).isEqualToWithSortedQueryParameters(new URL("http://example2.com?amp;a=b&c=d"));

Add isDirectoryRecursivelyContaining to File/Path assertions

Verify that the actual File/Path directory or any of its subdirectories (recursively) contains at least one file matching the given criteria expressed as:

These assertions are similart to isDirectoryContaining but recursively go into subdirectories.

Note that the actual File/Path must exist and be a directory.

Examples with files given the following directory structure:

root
|—— foo
|    |—— foobar
|         |—— foo-file-1.ext
|—— foo-file-2.ext

Examples with syntax patterns:

File root = new File("root");

// The following assertions succeed:
assertThat(root).isDirectoryRecursivelyContaining("glob:**foo")
                .isDirectoryRecursivelyContaining("glob:**ooba*")
                .isDirectoryRecursivelyContaining("glob:**file-1.ext")
                .isDirectoryRecursivelyContaining("regex:.*file-2.*")
                .isDirectoryRecursivelyContaining("glob:**.{ext,dummy}");

// The following assertions fail:
assertThat(root).isDirectoryRecursivelyContaining("glob:**fooba");
assertThat(root).isDirectoryRecursivelyContaining("glob:**.bin");
assertThat(root).isDirectoryRecursivelyContaining("glob:**.{java,class}");

Examples with predicates:

File root = new File("root");

// The following assertions succeed:
assertThat(root).isDirectoryRecursivelyContaining(file -> file.getName().startsWith("foo-file-1"))
                .isDirectoryRecursivelyContaining(file -> file.getName().endsWith("file-2.ext"))
                .isDirectoryRecursivelyContaining(file -> file.getName().equals("foo"))
                .isDirectoryRecursivelyContaining(file -> file.getParentFile().getName().equals("foo"))

// The following assertions fail:
assertThat(root).isDirectoryRecursivelyContaining(file -> file.getName().equals("foo-file-1"))
assertThat(root).isDirectoryRecursivelyContaining(file -> file.getName().equals("foo/foobar"));

Add hasBinaryContent to InputStream assertions

Verifies that the binary content of the actual InputStream is exactly equal to the given one.

Example: the following failing assertion …​

InputStream inputStream = new ByteArrayInputStream(new byte[] {1, 2});

// assertion will pass
assertThat(inputStream).hasBinaryContent(new byte[] {1, 2});

// assertions will fail
assertThat(inputStream).hasBinaryContent(new byte[] { });
assertThat(inputStream).hasBinaryContent(new byte[] {0, 0});

Add containsOnlyOnceElementsOf to Iterable/Object array/AtomicReferenceArray assertions

Verifies that the actual group contains the elements of the given iterable only once (same semantic as containsOnlyOnce(Object…​)).

Examples:

// assertions will pass
assertThat(list("winter", "is", "coming")).containsOnlyOnceElementsOf(list("winter"))
                                          .containsOnlyOnceElementsOf(list("coming", "winter"));

// assertions will fail
assertThat(list("winter", "is", "coming")).containsOnlyOnceElementsOf(list("Lannister"));
assertThat(list("Arya", "Stark", "daughter", "of", "Ned", "Stark")).containsOnlyOnceElementsOf(list("Stark"));
assertThat(list("Arya", "Stark", "daughter", "of", "Ned", "Stark")).containsOnlyOnceElementsOf(list("Stark", "Lannister", "Arya"));

Disambiguate colliding date/time representation

Different date/time types can be represented the same way (LocalDateTime and Date for example) which makes it difficult to understand error messages as they don’t show any difference between actual and expected values. AssertJ now adds the date/time type name for types whose representation may collide.

Example: the following failing assertion …​

Date now = new Date();
Object localDateTime = LocalDateTime.ofInstant(now.toInstant(), ZoneId.systemDefault());

assertThat(List.of(localDateTime)).containsExactly(now);

... fails with this error:

Expecting:
  <[2020-03-19T22:32:42.875 (java.time.LocalDateTime)]>
to contain exactly (and in same order):
  <[2020-03-19T22:32:42.875 (java.util.Date)]>
but some elements were not found:
  <[2020-03-19T22:32:42.875 (java.util.Date)]>
and others were not expected:
  <[2020-03-19T22:32:42.875 (java.time.LocalDateTime)]>

Before that the error would have been confusing:

Expecting:
  <[2020-03-19T22:32:42.875]>
to contain exactly (and in same order):
  <[2020-03-19T22:32:42.875]>
but some elements were not found:
  <[2020-03-19T22:32:42.875]>
and others were not expected:
  <[2020-03-19T22:32:42.875]>

2.9.15. AssertJ Core 3.15.0

Release date: 2020-01-28

The recursive comparison API has been promoted and is not a beta API anymore.

Contributors

Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Pascal Schumacher, BJ Hargrave, Raymond Augé, Thomas Weißschuh, Maciej Wajcht, Hayden Meloche, Filip Hrisafov, Jayati Goyal, Gyumin Kim, Clemens Grabmann, Roman Leventov, Fr Jeremy Krieg, Benoit Dupont, Nikolaos Georgiou, Christian Stein, Jeremy Landis, Graham Dennis, Fabien Duminy, Tommy Situ and Vincent Ricard.

Shout out to Vincent Ricard for the various tests refactoring, that was quite a lot of work!

Breaking changes

New features

Improvements

Fixed

Deprecated

Add java.time.Duration assertions

The following java.time.Duration assertions are available:

Examples:

assertThat(Duration.ofDays(5)).hasDays(5);
assertThat(Duration.ofHours(15)).hasHours(15);

assertThat(Duration.ofMinutes(65)).hasMinutes(65);
assertThat(Duration.ofSeconds(250)).hasSeconds(250);

assertThat(Duration.ofMillis(250)).hasMillis(250);
assertThat(Duration.ofNanos(145)).hasNanos(145);

assertThat(Duration.ofHours(5)).isPositive();
assertThat(Duration.ofMinutes(-15)).isNegative();
assertThat(Duration.ZERO).isZero();

Add isPackagePrivate to Class assertions

Verifies that the actual Class is package-private (i.e. has no modifier).

Example:

class MyClass {}

// this assertion succeeds:
assertThat(MyClass.class).isPackagePrivate();

// this assertion fails:
assertThat(String.class).isPackagePrivate();

Add hasSameBinaryContentAs to File/Path assertions

Verifies that the content of the actual file/path is equal to the content of the given one, the comparison is done at the binary level.

Example with Path (works the same with File):

// The first two paths have the same content, the third does not
Path aPath = Files.write(Paths.get("a-file.bin"), new byte[] { 42 });
Path bPath = Files.write(Paths.get("b-file.bin"), new byte[] { 42 });
Path cPath = Files.write(Paths.get("c-file.bin"), new byte[] { 24 });

// The following assertion succeeds:
assertThat(aPath).hasSameBinaryContentAs(bPath);

// The following assertion fails:
assertThat(aPath).hasSameBinaryContent(cPath);

Add succeedsWithin to CompletableFuture assertions

Waits if necessary for at most the given time for this future to complete, and then returns its result for futher assertions. If the future’s result is not available for any reason an assertion error is thrown.

The time to wait for can be expressed with a Duration or a TimeUnit.

To get assertions for the future result’s type use succeedsWithin that takes an additional InstanceOfAssertFactory parameter.

Examples:

CompletableFuture<String> future = CompletableFuture.completedFuture("ook!");

// assertion expressed with TimeUnit
assertThat(future).succeedsWithin(100, TimeUnit.MILLISECONDS)
                  .isEqualTo("ook!");

// same assertion with Duration
assertThat(future).succeedsWithin(Duration.ofMillis(100))
                  .isEqualTo("ook!");

// STRING is a static import of InstanceOfAssertFactories.STRING
// we can then chain String assertions
assertThat(future).succeedsWithin(100, TimeUnit.MILLISECONDS, STRING)
                  .startsWith("oo");

Add hasSuperclass to Class assertions

Verifies that the actual Class has the given superclass.

Example:

// this assertion succeeds:
assertThat(Integer.class).hasSuperclass(Number.class);

// this assertion succeeds as superclass for array classes is Object:
assertThat(Integer[].class).hasSuperclass(Object.class);

// this assertion fails:
assertThat(String.class).hasSuperclass(Number.class);

// this assertion fails as only direct superclass matches:
assertThat(String.class).hasSuperclass(Object.class);

// this assertion fails as interfaces are not superclasses:
assertThat(String.class).hasSuperclass(Comparable.class);

Add hasNoSuperclass to Class assertions

Verifies that the actual Class has no superclass.

Example:

// this assertion succeeds as interfaces have no superclass:
assertThat(Cloneable.class).hasNoSuperclass();

// this assertion succeeds as primitive types have no superclass:
assertThat(Integer.TYPE).hasNoSuperclass();

// this assertion succeeds as void type has no superclass:
assertThat(Void.TYPE).hasNoSuperclass();

// this assertion fails as Integer has Number as superclass:
assertThat(Integer.class).hasNoSuperclass();

Make recursive comparison API directly available to Iterable, Map, Optional and array assertions

Expose the recursive comparison for Iterable, Map, Optional and array assertions without having to cast them to Object as previously (because the API was only available for Object assertions).

At the moment, the only assertion available after in the recursive comparison is isEqualTo, there are plans to provide type specific recursive assertions in future (ex: iterable contains).

The recursive comparison API lets you finely control how to compare instances, please consult the documentation for a detailed guide.

For the following examples we use Person and Doctor, two classes with the same structure:

public class Person {
  String name;
  boolean hasPhd;
}

public class Doctor {
 String name;
 boolean hasPhd;
}

Doctor drSheldon = new Doctor("Sheldon Cooper", true);
Doctor drLeonard = new Doctor("Leonard Hofstadter", true);
Doctor drRaj = new Doctor("Raj Koothrappali", true);

Person sheldon = new Person("Sheldon Cooper", true);
Person leonard = new Person("Leonard Hofstadter", true);
Person raj = new Person("Raj Koothrappali", true);

Iterable example:

List<Doctor> doctors = list(drSheldon, drLeonard, drRaj);
List<Person> people = list(sheldon, leonard, raj);

// assertion succeeds as both lists contains equivalent items in order.
assertThat(doctors).usingRecursiveComparison()
                   .isEqualTo(people);

Array example:

Doctor[] doctors = { drSheldon, drLeonard, drRaj };
Person[] people = { sheldon, leonard, raj };

// assertion succeeds as both lists contains equivalent items in order.
assertThat(doctors).usingRecursiveComparison()
                   .isEqualTo(people);

Map example:

Map<String, Doctor> doctors = mapOf(entry(drSheldon.name, drSheldon),
                                    entry(drLeonard.name, drLeonard),
                                    entry(drRaj.name, drRaj));

Map<String, Person> people = mapOf(entry(sheldon.name, sheldon),
                                   entry(leonard.name, leonard),
                                   entry(raj.name, raj));

// assertion succeeds as both maps contains equivalent items.
assertThat(doctors).usingRecursiveComparison()
                   .isEqualTo(people);

Optional example:

Optional<Doctor> doctor = Optional.of(drSheldon);
Optional<Person> person = Optional.of(sheldon);

// assertion succeeds as both maps contains equivalent items.
assertThat(doctor).usingRecursiveComparison()
                  .isEqualTo(person);

2.9.16. AssertJ Core 3.14.0

Release date: 2019-10-27

Contributors

Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Jonas Berlin, Thami Inaflas, Geoffrey Arthaud, Carter Kozak, Kevin Toublanc, Krishna Chaithanya Ganta, sowmiyamuthuraman, Edgar Asatryan, Oleksii Khomchenko, Gonzalo Müller Bravo, Stephen O’Rourke, Sven Johansson, William Bakker, Rob Spieldenner, Raymond Pressly, Michael Keppler and Clemens Grabmann.

Breaking changes

New features

Improvements

Fixed

Deprecated

Add BDD assumptions

Add Behavior Driven Development style entry point for assumption methods for different types, which allow to skip test execution when assumptions are not met.

The difference with the Assumptions class is that entry point methods are named given instead of assumeThat.

Example:

String hobbit = "HOBBIT";
List<String> fellowshipOfTheRing = list("Aragorn", "Gandalf", "Frodo", "Legolas");

@Test
public void given_the_assumption_is_not_met_the_test_is_skipped() {
  given(hobbit).isEqualTo("ORC");
  // ... following code is not executed, the test is skipped
  then(fellowshipOfTheRing).contains("Sauron");
}

@Test
public void given_the_assumption_is_met_the_test_is_executed() {
  given(hobbit).isEqualTo("HOBBIT");
  // ... following code is executed and fails!
  then(fellowshipOfTheRing).doesNotContain("Sauron");
}

Add Spliterator assertions

Add hasCharacteristics and hasOnlyCharacteristics assertions for the Spliterator type.

Example:

Spliterator<Integer> spliterator = Stream.of(1, 2, 3).spliterator();

assertThat(spliterator).hasCharacteristics(Spliterator.SIZED,
                                           Spliterator.ORDERED)
                       .hasOnlyCharacteristics(Spliterator.SIZED,
                                               Spliterator.SUBSIZED,
                                               Spliterator.IMMUTABLE,
                                               Spliterator.ORDERED);

Add isAtSameInstantAs to OffsetDateTime assertions

Verifies that actual and given OffsetDateTime are at the same Instant.

Example:

OffsetDateTime offsetDateTime1 = OffsetDateTime.of(2000, 12, 12, 3, 0, 0, 0, ZoneOffset.ofHours(3));
OffsetDateTime offsetDateTime2 = OffsetDateTime.of(2000, 12, 12, 0, 0, 0, 0, ZoneOffset.ofHours(0));
// assertion succeeds
assertThat(offsetDateTime1).isAtSameInstantAs(offsetDateTime2);

offsetDateTime2 = OffsetDateTime.of(2000, 12, 12, 2, 0, 0, 0, ZoneOffset.ofHours(0));
// assertion fails
assertThat(offsetDateTime1).isAtSameInstantAs(offsetDateTime2);

Add assertAlso SoftAssertions method to allow combining different soft assertions instances

assertAlso lets you combine other soft assertions instances together.

Example:

Mansion mansion = new Mansion();

SoftAssertions check_kitchen() {
  SoftAssertions softly = new SoftAssertions();
  softly.assertThat(mansion.kitchen()).as("Kitchen").isEqualTo("clean");
  return softly;
}

SoftAssertions check_library() {
  SoftAssertions softly = new SoftAssertions();
  softly.assertThat(mansion.library()).as("Library").isEqualTo("clean");
  return softly;
}

@Test
void host_dinner_party_where_nobody_dies() {
  SoftAssertions softly = new SoftAssertions();
  mansion.hostPotentiallyMurderousDinnerParty();
  softly.assertThat(mansion.guests()).as("Living Guests").isEqualTo(7);
  softly.assertThat(mansion.revolverAmmo()).as("Revolver Ammo").isEqualTo(6);
  softly.assertThat(mansion.candlestick()).as("Candlestick").isEqualTo("pristine");
  softly.assertThat(mansion.colonel()).as("Colonel").isEqualTo("well kempt");
  softly.assertThat(mansion.professor()).as("Professor").isEqualTo("well kempt");

  SoftAssertions kitchen = check_kitchen();
  softly.assertAlso(kitchen);

  SoftAssertions library = check_library();
  softly.assertAlso(library);

  softly.assertAll();
}

Add isEmpty and isNotEmpty file assertions

Verify that the actual File is empty (i.e. the file size = 0) or not empty (i.e. the file size > 0) .

Example:

File file = File.createTempFile("tmp", "txt");

// assertion will pass
assertThat(file).isEmpty();

Files.write(file.toPath(), new byte[]{1, 1});

// assertion will pass
assertThat(file).isNotEmpty();

Add hasSize(long expectedSizeInBytes) to File assertions

Verifies that the size of the File under test is exactly equal to the given size in bytes.

Example:

File file = File.createTempFile("tmp", "bin");
Files.write(file.toPath(), new byte[] {1, 1});

// assertion will pass
assertThat(file).hasSize(2);

// assertion will fail
assertThat(file).hasSize(1);

Avoid BDDMockito/BDDAssertions then(object) clash with and.then(object)

To avoid clash with libraries like Mockito that exposes a static then(object) method, you can statically use the and field.

import static org.mockito.BDDMockito.then;
// can't use import static org.assertj.core.api.BDDAssertions.then because of BDDMockito.then;
import static org.assertj.core.api.BDDAssertions.and;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;

// suppress and.then warning: The static method BDDAssertions.then() should be accessed in a static way
@SuppressWarnings("static-access")
@Test
public void bdd_assertions_with_bdd_mockito() {
  // GIVEN
  Person person = mock(Person.class)
  // WHEN
  person.ride(bike);
  person.ride(bike);
  // THEN
  // mockito then()
  then(person).should(times(2)).ride(bike);
  // use AssertJ and.then(person) as then(person) would clash with mockito then(person)
  and.then(person.hasBike()).isTrue();
}

Add hasRootCauseMessage to Throwable assertions

Verifies that the message of the root cause of the actual Throwable is equal to the given one, a simple String or String.format is supported to specify the expected root cause message.

Example:

Throwable throwable = new Throwable(new IllegalStateException(new NullPointerException("expected message")));

// assertions will pass
assertThat(throwable).hasRootCauseMessage("expected message")
                     .hasRootCauseMessage("expected %s", "message");

// assertions will fail
assertThat(throwable).hasRootCauseMessage("another message");
assertThat(throwable).hasRootCauseMessage("%s", "message");
// no root cause message
assertThat(new Throwable()).hasRootCauseMessage("%s %s", "expected", "message");

Add syntax sugar as(InstanceOfAssertFactory) to Assertions and WithAssertions for improved readability

A syntax sugar to write fluent assertion with methods having an InstanceOfAssertFactory parameter. Added as a static method in Assertions, it is also available as a default method in the WithAssertions interface.

Example:

Jedi yoda = new Jedi("Yoda", "Green");

assertThat(yoda).extracting(Jedi::getName, as(InstanceOfAssertFactories.STRING))
                .startsWith("Yo");

as(InstanceOfAssertFactory) can be used together with the following assertion methods:

Extracts the value of given field/property from the object under test, the extracted value becoming the new object under test. The InstanceOfAssertFactory parameter is used to get the assertions narrowed to the factory type.

Examples:

// Create frodo, setting its name, age and Race (Race having a name property)
TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, HOBBIT);

// let's extract and verify Frodo's name:
assertThat(frodo).extracting("name", as(InstanceOfAssertFactories.STRING))
                 .startsWith("Fro");

// The following assertion will fail as Frodo's name is not an Integer:
assertThat(frodo).extracting("name", as(InstanceOfAssertFactories.INTEGER))
                 .isZero();

Uses the given Function to extract a value from the object under test, the extracted value becoming the new object under test. The InstanceOfAssertFactory parameter is used to get the assertions narrowed to the factory type.

Examples:

// Create frodo, setting its name, age and Race (Race having a name property)
TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, HOBBIT);

// let's extract and verify Frodo's name:
assertThat(frodo).extracting(TolkienCharacter::getName, as(InstanceOfAssertFactories.STRING))
                 .startsWith("Fro");

// The following assertion will fail as Frodo's name is not an Integer:
assertThat(frodo).extracting(TolkienCharacter::getName, as(InstanceOfAssertFactories.INTEGER))
                 .isZero();

Extracts the value of given key from the map under test, the extracted value becoming the new object under test. The InstanceOfAssertFactory parameter is used to get the assertions narrowed to the factory type.

Examples:

Map<String, Object> map = new HashMap<>();
map.put("name", "kawhi");

// The following assertion will succeed:
assertThat(map).extractingByKey("name", as(InstanceOfAssertFactories.STRING))
               .startsWith("kaw");

// The following assertion will fail as the value is not an Integer:
assertThat(map).extractingByKey("name", as(InstanceOfAssertFactories.INTEGER))
               .isZero();

Add get with InstanceOfAssertFactory parameters to Optional assertions

Verifies that the optional is not null and not empty and returns an new assertion instance to chain assertions on the optional value. The InstanceOfAssertFactory parameter is used to get the assertions narrowed to the factory type.

Examples:

Optional<String> optional = Optional.of("Frodo");

// The following assertion will succeed:
assertThat(optional).get(as(InstanceOfAssertFactories.STRING))
                    .startsWith("Fro");

// The following assertion will fail as the value is not an Integer:
assertThat(optional).get(as(InstanceOfAssertFactories.INTEGER))
                    .isZero();

Add first with InstanceOfAssertFactory parameters to Iterable assertions

Navigates and allows to perform assertions on the first element of the Iterable under test. The InstanceOfAssertFactory parameter is used to get the assertions narrowed to the factory type.

Examples:

Iterable<String> hobbits = newArrayList("Frodo", "Sam", "Pippin");

// assertion succeeds
assertThat(hobbits).first(as(InstanceOfAssertFactories.STRING))
                   .startsWith("Fro")
                   .endsWith("do");
// assertion fails
assertThat(hobbits).first(as(InstanceOfAssertFactories.STRING))
                   .startsWith("Pip");
// assertion fails because of wrong factory type
assertThat(hobbits).first(as(InstanceOfAssertFactories.INTEGER))
                   .isZero();

Add last with InstanceOfAssertFactory parameters to Iterable assertions

Navigates and allows to perform assertions on the last element of the Iterable under test. The InstanceOfAssertFactory parameter is used to get the assertions narrowed to the factory type.

Examples:

Iterable<String> hobbits = newArrayList("Frodo", "Sam", "Pippin");

// assertion succeeds
assertThat(hobbits).last(as(InstanceOfAssertFactories.STRING))
                   .startsWith("Pip")
                   .endsWith("pin");
// assertion fails
assertThat(hobbits).last(as(InstanceOfAssertFactories.STRING))
                   .startsWith("Fro");
// assertion fails because of wrong factory type
assertThat(hobbits).last(as(InstanceOfAssertFactories.INTEGER))
                   .isZero();

Add element with InstanceOfAssertFactory parameters to Iterable assertions

Navigates and allows to perform assertions on the chosen element of the Iterable under test. The InstanceOfAssertFactory parameter is used to get the assertions narrowed to the factory type.

Examples:

Iterable<String> hobbits = newArrayList("Frodo", "Sam", "Pippin");

// assertion succeeds
assertThat(hobbits).element(1, as(InstanceOfAssertFactories.STRING))
                   .startsWith("Sa")
                   .endsWith("am");
// assertion fails
assertThat(hobbits).element(1, as(InstanceOfAssertFactories.STRING))
                   .startsWith("Fro");
// assertion fails because of wrong factory type
assertThat(hobbits).element(1, as(InstanceOfAssertFactories.INTEGER))
                   .isZero();

Add String.format support for expected message in hasMessageStartingWith, hasMessageContaining, hasMessageEndingWith and hasStackTraceContaining assertions

Instead of taking a simple String the assertions mentioned above now accept a String.format like parameters, i.e. (String description, Object…​ parameters) making it easier to build more involved expected strings.

Examples:

Throwable throwableWithMessage = new IllegalArgumentException("wrong amount 123");

assertThat(throwableWithMessage).hasMessageStartingWith("%s a", "wrong")
                                .hasMessageContaining("wrong %s", "amount")
                                .hasMessageEndingWith("%s 123", "amount")
                                .hasStackTraceContaining("%s amount", "wrong");

extracting is now able to extract a deeply nested map key, before this improvement extracting a value by key was only supported for a Map object under test (but not for fields of type Map).

Let’s clarify things with a concrete example:

Jedi luke = new Jedi(new Name("Luke", "Skywalker"), 26);
// setAttribute puts a new entry in 'attributes' Map field
luke.setAttribute("side", "light");

Jedi leia = new Jedi(new Name("Leia", "Skywalker"), 26);
// setRelation puts a new entry in 'relations' Map field
luke.setRelation("sister", leia);
leia.setRelation("brother", luke);

assertThat(luke).extracting("name.last",
                            "attributes.side",
                            "relations.sister",
                            "relations.sister.relations.brother")
                .containsExactly("Skywalker",
                                 "light",
                                 leia,
                                 luke);

Prettify allOf and anyOf combined conditions description

To make it more readable, reformat the error message when multiple combined conditions with allOf and anyOf fail.

Examples: the following assertion will fail …​

private static Condition<String> contains(String s) {
  return new Condition<>(value -> value.contains(s), "contains " + s);
}

// failing assertion:
assertThat("Gandalf").has(anyOf(contains("i"),
                                allOf(contains("o"),
                                      anyOf(contains("a"),
                                            contains("b"),
                                            contains("c")))));

With the following error message

Expecting:
 <"Gandalf">
to have:
 <any of:[
   contains i,
   all of:[
      contains o,
      any of:[
         contains a,
         contains b,
         contains c
      ]
   ]
]>

Add matching syntactic sugar method to use Hamcrest Matcher as Condition

Syntactic sugar to construct a Condition using the Hamcrest Matcher given as a parameter.

Example:

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.HamcrestCondition.matching;
import static org.hamcrest.core.StringContains.containsString;

@Test
public void matching_example() {
 assertThat("abc").is(matching(containsString("a")));
}

2.9.17. AssertJ Core 3.13.2

Release date: 2019-08-04

This release ships a few improvements:

2.9.18. AssertJ Core 3.13.1

Release date: 2019-07-29

This release addresses the 3.13.0 issue by which AssertJ required OpenTest4J to be on the classpath otherwise a java.lang.NoClassDefFoundError: org/opentest4j/MultipleFailuresError would be raised. Thanks Pascal Schumacher for the quick fix!

java.lang.NoClassDefFoundError: org/opentest4j/MultipleFailuresError
   at java.base/java.lang.ClassLoader.defineClass1(Native Method)
   at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
   at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174)
   at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:802)
   at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:700)
   at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:623)
   at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
   at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
   at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
   at org.assertj.core.internal.Failures.<init>(Failures.java:46)
   at org.assertj.core.internal.Failures.<clinit>(Failures.java:44)
   at org.assertj.core.internal.Objects.<init>(Objects.java:87)
   at org.assertj.core.internal.Objects.<init>(Objects.java:101)
   at org.assertj.core.internal.Objects.<clinit>(Objects.java:82)
   at org.assertj.core.api.AbstractAssert.<init>(AbstractAssert.java:65)
   at org.assertj.core.api.AbstractCharSequenceAssert.<init>(AbstractCharSequenceAssert.java:53)
   at org.assertj.core.api.AbstractStringAssert.<init>(AbstractStringAssert.java:28)
   at org.assertj.core.api.StringAssert.<init>(StringAssert.java:25)
   at org.assertj.core.api.AssertionsForClassTypes.assertThat(AssertionsForClassTypes.java:484)
   at org.assertj.core.api.Assertions.assertThat(Assertions.java:2585)

2.9.19. AssertJ Core 3.13.0

Release date: 2019-07-28

The highlight of this release is the addition of asInstanceOf which allows to chain specific type assertions from a value that was initially declared with a different type (usually Object). Thanks Stefano Cordio for this contribution!

Example:

Object value = "abc";

// This line DOES NOT COMPILE since startsWith is a String assertion and value is an Object
assertThat(value).startsWith("ab");

// This line COMPILES because we tell AssertJ to consider value as a String
assertThat(value).asInstanceOf(InstanceOfAssertFactories.STRING).startsWith("ab");

This feature is more detailed in the notes below.

Contributors

Thanks to all the contributors of this release:

Pascal Schumacher, Erhard Pointl, Stefano Cordio, Thomas Traude, Andrei Solntsev, Matej Drobnič, Željko Mirović, Mike Gilchrist, Phillip Webb, Michal Fotyga,Valeriy Vyrva, Eddú Meléndez Gonzales, GaspardPO, Bengt Brodersen, Jiri Pejchal, Christian Stein, Nikolaos Georgiou and Sam Brannen.

Special thanks to Nils Winkler for his work on the assertions conversion scripts and Stefano Cordio for the asInstanceOf contribution.

Breaking changes

// GIVEN
Map<String, Object> basketballPlayer = new HashMap<>();
basketballPlayer.put("name", "kawhi");
basketballPlayer.put("age", 25);

// Does not compile anymore!
assertThat(basketballPlayer).extracting("name")
                            .containsExactly("kawhi"); // DOES NOT COMPILE

// Use Object assertions like isEqualTo
assertThat(basketballPlayer).extracting("name")
                            .isEqualTo("kawhi");

// multiple values work as before, no problem there!
assertThat(basketballPlayer).extracting("name", "age")
                            .containsExactly("kawhi", 25);

New features

Improvements

Fixed

Deprecated

Add asInstanceOf to chain specific type assertions

asInstanceOf allows to chain specific type assertions from a value initially declared as a less specific type (often Object).

Let’s start with the problem asInstanceOf is solving: in the following example we would like to call String assertions but this is not possible since value is declared as an Object thus only Object assertions are accessible.

// Given a String declared as an Object
Object value = "Once upon a time in the west";

// We would like to call String assertions but this is not possible since value is declared as an Object
assertThat(value).startsWith("ab"); // this does not compile !

Thanks to asInstanceOf we can now tell AssertJ to consider value as a String in order to call String assertions. To do so we need to pass an InstanceOfAssertFactory that can build a StringAssert, fortunately you don’t have to write it, it is already available in InstanceOfAssertFactories!

import static org.assertj.core.api.InstanceOfAssertFactories.STRING;

// Given a String declared as an Object
Object value = "Once upon a time in the west";

// With asInstanceOf, we switch to specific String assertion by specifying the InstanceOfAssertFactory for String
assertThat(value).asInstanceOf(STRING).startsWith("Once");

AssertJ verifies that the actual value is compatible with the assertions InstanceOfAssertFactory is going to give access to.

InstanceOfAssertFactories provides static factories for all types AssertJ provides assertions for, additional factories can be created with custom InstanceOfAssertFactory instances.

Here’s another example showing the parameterized type support:

// Actually a List<TolkienCharacter>
Object hobbits = list(frodo, pippin, merry, sam);

// As we specify the TolkienCharacter class, the following chained assertion expect to be given TolkienCharacters.
// This means that method like extracting or filteredOn are given a TolkienCharacter
assertThat(hobbits).asInstanceOf(InstanceOfAssertFactories.list(TolkienCharacter.class))
                   .contains(frodo, sam)
                   .extracting(TolkienCharacter::getName)
                   .contains("Frodo", "Sam");

// Use LIST if the elements type is not important but note that the chained assertions
// will be given Object not TolkienCharacter
assertThat(hobbits).asInstanceOf(InstanceOfAssertFactories.LIST)
                    //.extracting(TolkienCharacter::getName) does not work as extracting is given an Object
                   .contains(frodo);

Extracts the value of given field/property from the object under test, the extracted value becoming the new object under test.

Examples:

// Create frodo, setting its name, age and Race (Race having a name property)
TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, HOBBIT);

// let's extract and verify Frodo's name:
assertThat(frodo).extracting("name")
                 .isEqualTo("Frodo");

// The extracted value being a String, we would like to use String assertions but we can't due to Java generics limitations.
// The following assertion does NOT compile:
assertThat(frodo).extracting("name")
                 .startsWith("Fro");

// To get String assertions use asInstanceOf:
assertThat(frodo).extracting("name")
                 .asInstanceOf(InstanceOfAssertFactories.STRING)
                 .startsWith("Fro");

If the object under test is a Map, the parameter is used as a key to the map.

Example:

Map<String, Object> basketballPlayer = new HashMap<>();
basketballPlayer.put("name", "kawhi");
basketballPlayer.put("age", 25);

// single value
assertThat(basketballPlayer).extracting("name")
                            .isEqualTo("kawhi");

AssertJ global configuration

AssertJ 3.13.0 introduces a Configuration class allowing to change AssertJ behavior and a way to register automatically. Read Configuring AssertJ chapter to learn about it.

Add hasCauseReference to throwable assertions

Verifies that the actual Throwable has a cause that refers to the given one, i.e. using == comparison.

Example:

Throwable invalidArgException = new IllegalArgumentException("invalid arg");
Throwable throwable = new Throwable(invalidArgException);

// This assertion succeeds:
assertThat(throwable).hasCauseReference(invalidArgException);

// These assertions fail:
assertThat(throwable).hasCauseReference(new IllegalArgumentException("invalid arg"));
assertThat(throwable).hasCauseReference(new NullPointerException());
assertThat(throwable).hasCauseReference(null); // prefer hasNoCause()

New directory content assertions

The new assertions have been added for both File and Path, they add support for

Both isDirectoryContaining and isDirectoryNotContaining accept either Predicate or String parameters, the String one being interpreted as a path matcher.

As File and Path assertions are similar, the examples will only show File assertions.

The examples use the following directory structure:

/root/
/root/sub-dir-1/
/root/sub-dir-1/file-1.ext
/root/sub-dir-1/file-2.ext
/root/sub-dir-2/
/root/sub-file-1.ext
/root/sub-file-2.ext

isDirectoryContaining assertions examples:

File root = new File("root");

// Successfull assertions with predicate parameter:
assertThat(root).isDirectoryContaining(file -> file.getName().startsWith("sub-dir"))
                .isDirectoryContaining(file -> file.getName().startsWith("sub-file"))
                .isDirectoryContaining(file -> file.getName().endsWith(".ext"))
                .isDirectoryContaining(File::isDirectory);

// Successfull assertions with String path matcher parameter:
assertThat(root).isDirectoryContaining("glob:**sub-dir*")
                .isDirectoryContaining("glob:**sub-file*")
                .isDirectoryContaining("glob:**.ext")
                .isDirectoryContaining("regex:.*ext")
                .isDirectoryContaining("glob:**.{ext,bin");


// The following assertions fail:
assertThat(root).isDirectoryContaining(file -> file.getName().startsWith("dir"));
assertThat(root).isDirectoryContaining(file -> file.getName().endsWith(".bin"));
assertThat(root).isDirectoryContaining("glob:**dir");
assertThat(root).isDirectoryContaining("glob:**.bin");

isDirectoryNotContaining assertion examples:

File root = new File("root");

// Successfull assertions with predicate parameter:
assertThat(root).isDirectoryNotContaining(file -> file.getName().startsWith("dir"))
                .isDirectoryNotContaining(file -> file.getName().endsWith(".bin"));

// Successfull assertions with String path matcher parameter:
assertThat(root).isDirectoryNotContaining("glob:**dir")
                .isDirectoryNotContaining("glob:**.bin")
                .isDirectoryNotContaining("regex:.*bin")
                .isDirectoryNotContaining("glob:**.{java,class}");

// The following assertions fail:
assertThat(root).isDirectoryContaining(file -> file.getName().startsWith("dir"));
assertThat(root).isDirectoryContaining(file -> file.getName().endsWith(".bin"));
assertThat(root).isDirectoryNotContaining("glob:**sub-dir*");
assertThat(root).isDirectoryNotContaining("regex:.*ext");
assertThat(root).isDirectoryNotContaining("glob:**.{ext,bin");

isEmptyDirectory assertion examples:

File root = new File("root");

// The following assertion succeeds:
assertThat(new File(root, "sub-dir-2")).isEmptyDirectory();

// The following assertions fail:
assertThat(root).isEmptyDirectory();
assertThat(new File(root, "sub-dir-1")).isEmptyDirectory();

isNotEmptyDirectory assertion examples:

File root = new File("root");

// The following assertions succeed:
assertThat(root).isNotEmptyDirectory();
assertThat(new File(root, "sub-dir-1")).isNotEmptyDirectory();

// The following assertion fails:
 assertThat(new File(root, "sub-dir-2")).isNotEmptyDirectory();

Add hasMessageContainingAll and hasMessageNotContainingAny to throwable assertions

These assertions are the equivalent of hasMessageContaining and hasMessageNotContaining but accepting multiple String parameters instead of only one.

Example:

Throwable throwableWithMessage = new IllegalArgumentException("wrong amount 123");
Throwable throwableWithoutMessage = new IllegalArgumentException();

// assertion will pass:
assertThat(throwableWithMessage).hasMessageContainingAll("amount", "123")
                                .hasMessageNotContainingAny("foo", "234");

assertThat(throwableWithoutMessage).hasMessageNotContainingAny("234");

// assertions will fail:
assertThat(throwableWithMessage).hasMessageContainingAll("234");
assertThat(throwableWithoutMessage).hasMessageContainingAll("123");

assertThat(throwableWithMessage).hasMessageNotContainingAny("foo", "amount");

The same assertions have been added to ThrowableAssertAlternative with these names withMessageContainingAll and withMessageNotContainingAny:

Throwable illegalArgumentException = new IllegalArgumentException("wrong amount 123");

// assertions will pass
assertThatExceptionOfType(Throwable.class)
          .isThrownBy(() -> {throw illegalArgumentException;})
          .withMessageContainingAll("amount", "123")
          .withMessageNotContainingAny("foo", "234");

Allow using any custom assertions in soft assertions

The new check method catches and collect assertion errors coming from standard and custom assertions.

Example:

SoftAssertions softly = new SoftAssertions();

// custom assertions
softly.check(() -> LotrAssertions.assertThat(frodo).hasName("Frodon"));
softly.check(() -> LotrAssertions.assertThat(frodo).hasName("Frodo"));

// standard assertions
softly.assertThat("foo").startsWith("bar");
// could be written with check like (but it's as elegant as the standard use):
// softly.check(() -> Assertions.assertThat("foo").startsWith("bar"));

// 2 errors: "foo" does not start with "bar" and frodo's name is not "Frodon"
assertThat(softly.errorsCollected()).hasSize(2);

Add containsExactlyInAnyOrderEntriesOf to map assertions

Verifies that the actual map contains only the given entries and nothing else, in any order.

This is the same assertion as containsOnly(Map.Entry…​ entries), it simply handles the conversion of Map.entrySet() to array.

Example :

Map<Ring, TolkienCharacter> ringBearers = newLinkedHashMap(entry(oneRing, frodo),
                                                           entry(nenya, galadriel),
                                                           entry(narya, gandalf));
// assertion will pass
assertThat(ringBearers).containsExactlyInAnyOrderEntriesOf(newLinkedHashMap(entry(oneRing, frodo),
                                                                            entry(nenya, galadriel),
                                                                            entry(narya, gandalf)));
// assertion will pass although actual and expected order differ
assertThat(ringBearers).containsExactlyInAnyOrderEntriesOf(newLinkedHashMap(entry(nenya, galadriel),
                                                                            entry(narya, gandalf),
                                                                            entry(oneRing, frodo)));
// assertion will fail as actual does not contain all entries of expected
assertThat(ringBearers).containsExactlyInAnyOrderEntriesOf(newLinkedHashMap(entry(oneRing, frodo),
                                                                            entry(nenya, galadriel),
                                                                            entry(oneRing, frodo)));
// assertion will fail as actual and expected have different sizes
assertThat(ringBearers).containsExactlyInAnyOrderEntriesOf(newLinkedHashMap(entry(oneRing, frodo),
                                                                            entry(nenya, galadriel),
                                                                            entry(narya, gandalf),
                                                                            entry(narya, gandalf)));

Add isCloseToUtcNow to LocalDateTime and OffsetDateTime assertions

Verifies that the actual LocalDateTime/OffsetDateTime is close to the current date and time on the UTC timezone, according to the given offset.

You can build the offset parameter using Assertions.within(long, TemporalUnit) or Assertions.byLessThan(long, TemporalUnit).

If the difference is equal to the offset, the assertion succeeds.

Example with LocalDateTime:

LocalDateTime actual = LocalDateTime.now(Clock.systemUTC());

// assertion will pass if executed less than one second after actual was built
assertThat(actual).isCloseToUtcNow(byLessThan(1, ChronoUnit.SECONDS));

// assertion will fail
assertThat(actual.plusSeconds(2)).isCloseToUtcNow(within(1, ChronoUnit.SECONDS));

The same example works with OffsetDateTime by simply defining actual as:

OffsetDateTime actual = OffsetDateTime.now(Clock.systemUTC());

Add support for combined millisecond and timezone parsing

Add yyyy-MM-dd HH:mm:ss.SSSX to the default date formats AssertJ supports in Date assertions that take a String parameter representating a Date.

Here’s an example of string following this format: "2003-04-26T00:00:00.123+00:00".

Example:

// GIVEN
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
// WHEN
Date date = isoFormat.parse("2003-04-26T00:00:00.123");
// THEN
assertThat(date).isEqualTo("2003-04-26T00:00:00.123+00:00");

Add support for Optional in the new recursive comparison

The recursive comparison added in 3.12.0 now compares Optional values recursively instead of comparing Optional with equals. This is consistent with comparing list elements by elements as an Optional can be seen as a list with at most one element.

Example:

// Song constructor parameters: song, author and coAuthor (optional)
Song song = new Song("I Can't Get No Satisfaction", new Author("Mick Jagger"), new Author("Keith Richards"));
Song expectedSong = new Song("I Can't Get No Satisfaction", new Author("Mick Jagger"), new Author("Keith Richards"));
// THEN
assertThat(song).usingRecursiveComparison()
                .isEqualTo(expectedSong);

where Song and Author don’t override equals:

class Song {

  Author author;
  Optional<Author> coAuthor;
  String song;

  Song(String song, Author author, Author coAuthor) {
    this.song = song;
    this.author = author;
    this.coAuthor = Optional.ofNullable(coAuthor);
  }

  // no equals!
}

class Author {

  String name;

  Author(String name) {
    this.name = name;
  }

  String getName() {
    return name;
  }

  // no equals!
}

If we fail the test ...

Song song = new Song("I Can't Get No Satisfaction", new Author("Mick Jagger"), new Author("Jimi Hendrix"));
Song expectedSong = new Song("I Can't Get No Satisfaction", new Author("Mick Jagger"), new Author("Keith Richards"));
// FAIL
assertThat(song).usingRecursiveComparison()
                .isEqualTo(expectedSong);

... here’s the error reported:

Expecting:
  <Song [author=Mick Jagger, coAuthor=Optional[Jimi Hendrix], song=I Can't Get No Satisfaction]>
to be equal to:
  <Song [author=Mick Jagger, coAuthor=Optional[Keith Richards], song=I Can't Get No Satisfaction]>
when recursively comparing field by field, but found the following difference:

field/property 'coAuthor.value.name' differ:
- actual value   : "Jimi Hendrix"
- expected value : "Keith Richards"

The recursive comparison was performed with this configuration:
- overridden equals methods were used in the comparison
- these types were compared with the following comparators:
  - java.lang.Double -> DoubleComparator[precision=1.0E-15]
  - java.lang.Float -> FloatComparator[precision=1.0E-6]
- actual and expected objects and their fields were compared field by field recursively even if they were not of the same type, this allows for example to compare a Person to a PersonDto (call strictTypeChecking(true) to change that behavior).

Allow ignoring collection order in the new recursive comparison

The recursive comparison added in 3.12.0 can now ignore collection order in all fields in the object under test, this is handy when comparing list to set fields where only the content is relevant but not the order.

Example:

public class Person {
  String name;
  List<Person> friends = new ArrayList<>();
}

Person sherlock1 = new Person("Sherlock Holmes");
sherlock1.friends.add(new Person("Dr. John Watson"));
sherlock1.friends.add(new Person("Molly Hooper"));

Person sherlock2 = new Person("Sherlock Holmes");
sherlock2.friends.add(new Person("Molly Hooper"));
sherlock2.friends.add(new Person("Dr. John Watson"));

// assertion succeeds as all fields collection order is ignored in the comparison
assertThat(sherlock1).usingRecursiveComparison()
                     .ignoringCollectionOrder()
                     .isEqualTo(sherlock2);

// assertion fails as fields collection order is not ignored in the comparison
assertThat(sherlock1).usingRecursiveComparison()
                     .isEqualTo(sherlock2);

extracting(Function) learned to propagate the type parameter of the resulting ObjectAssert allowing then to chain other type aware methods (e.g. additional extracting).

Example:

// Old implementation
assertThat(yoda).extracting(Jedi::getName) // ObjectAssert<Object>
                .extracting(String::length) // Not compiling
                .isEqualTo(4);

// New implementation
assertThat(yoda).extracting(Jedi::getName) // ObjectAssert<String>
                .extracting(String::length)  // Compiling!
                .isEqualTo(4);

2.9.20. AssertJ Core 3.12.2

The main issue fixed was to ignore static methods when finding property accessors (contributed by Andy Wilkinson) which could break some tests since bare name method introspection was introduced in 3.12.0.

anySatisfy for Maps was improved and does not continue evaluating elements once a match is found (contributed by Erhard Pointl).

2.9.21. AssertJ Core 3.12.1

Fix a regression that included a bad module-info.class (thanks Jaro Kuruc) and other minor improvements.

2.9.22. AssertJ Core 3.12.0

Release date: 2019-02-14

The main feature of this release is a beta version of the new Recursive comparison API! It covers what isEqualToComparingFieldByFieldRecursively used but easier to use and with more capabilities.

It is a Beta version because we want to have feedback from the community to make it even better before freezing the API. There are more capabilities to come in the next releases, stay tuned!

Contributors

Big thanks to all the contributors of this release:

Pascal Schumacher, Erhard Pointl, Vladimir Chernikov, Sandra Parsick, Martin Tarjanyi, Stephan Windmüller, Yaroslav Mitsynskiy, Thomas Traude, Georg Berky, Tomek Kaczanowski, Lukáš Křečan, Yoann Rodière, Filip Hrisafov, Steven Schlansker, Jeremy Landis, Jack Gough, Sebastian Kempken, Stefan Mandel, Alexandre de Champeaux, Arvid Heise, Jeff Walker, Dmitrii Priporov and Joshua Kitchen.

Breaking changes

| | This removes the previously supported “Iterable” assertions (like containsOnly), call IteratorAssert#toIterable to access them again, ex: | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |

Iterator<String> bestBasketBallPlayers = getBestBasketBallPlayers();

assertThat(bestBasketBallPlayers).toIterable().contains("Jordan", "Magic", "Lebron");

AssertJ uses introspection in various places, one example is extracting properties as in extracting("name"). AssertJ is able to get values with getters like getName(), with this improvement it now can get property values with bare name method like name().

| | Bare-named property introspection is enabled by default and thus changes AssertJ behavior which can break some existing tests relying on introspection, this is especially true as AssertJ wrongly tries static methods (https://github.com/assertj/assertj-core/issues/1458 had been created to address that). | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

It is possible to avoid this problem by calling Assertions.setExtractBareNamePropertyMethods(false); before every impacted tests.

This is a bit tedious but an improvement is planned in the next release to provide a place to perform global configuration with the same mechanism allowing to register a custom representation.

New features
Improvements
Fixed