AssertJ assertions generator

Use the Assertion Generator to create assertions specific to your own classes, either through a simple command line tool or a maven plugin.

Having assertions specific to your own classes allows you to use the domain model vocabulary in your test assertions, making them easier to read and closer to the problem you are trying to solve. It's a way to apply Domain Driven Design ubiquitous language in tests.

Let's say that you have a Player class with name, team and teamMates properties (works also with public fields).

public class Player {

  private String name;
  private String team;
  private List<String> teamMates;

  // constructor and setters omitted
  public String getName() {
    return name;
  }
  public String getTeam() {
    return team;
  }
  public List<String> getTeamMates() {
    return teamMates;
  }

  @Override
  public String toString() {
    return "Player[name="+name+"]";
  }  
}

The generator is able to create a PlayerAssert assertions class with hasName and hasTeam assertions which can be used like :

assertThat(mj).hasName("Michael Jordan")
              .hasTeam("Chicago Bulls")
              .hasTeamMates("Scottie Pippen", "Tony Kukoc");

The error messages used when an assertion fails also reflects the property checked, for example if hasName fails you will an error message like.

Expecting name of:
  <Player[name=Air Jordan]>
to be:
  <Michael Jordan>
but was:
  <Air Jordan>

The generator creates assertions for each properties or public fields, the assertions created are specific to the property/field type. The following list shows which assertions are created for a given type :

  • boolean :
    • isX()
    • isNotX()
  • int, long, short, byte, char :
    • hasX(value) - values compared with ==
  • float and double :
    • hasX(value) - values compared with ==
    • hasXCloseTo(value, delta), diff < delta check
  • Iterable<T> and T[] :
    • hasX(T... values)
    • hasOnlyX(T... values)
    • doesNotHaveX(T... values)
    • hasNoX()
    Element comparison is based on T::equals method.
  • Object :
    • hasX(value) - equals based comparison
Notes

The generator introspects properties and public fields, the most specific type is chosen when generating assertions, Object assertion being the default choice.

The same assertions are generated for primitive types and their wrapper versions (ex: double and Double), the only difference being the performed check : null safe equals comparison for wrappers and == for primitives.

You can change what is generated by modifying the templates used to generate assertions, templates are located in the templates directory.

Let's enrich our Player with different properties/public fields to see what assertions are generated.

public class Player {
  // no getter needed to generate assertion for public fields
  // private fields getters and setters omitted for brevity

  public String name; // Object assertion generated
  private int age; // whole number assertion generated
  private double height; // real number assertion generated
  private boolean retired; // boolean assertion generated
  private List<String> teamMates;  // Iterable assertion generated
}

Created assertions :

public class PlayerAssert extends AbstractAssert<PlayerAssert, Player> {

  // javadoc and implementation omitted for brevity !

  public PlayerAssert hasAge(int age) { ... }

  public PlayerAssert hasHeight(double height) { ... }

  public PlayerAssert hasHeightCloseTo(double height, double offset) { ... }

  public PlayerAssert hasTeamMates(String... teamMates) { ... }

  public PlayerAssert hasOnlyTeamMates(String... teamMates) { ... }

  public PlayerAssert doesNotHaveTeamMates(String... teamMates) { ... }

  public PlayerAssert hasNoTeamMates() { ... }

  public PlayerAssert isRetired() { ... }

  public PlayerAssert isNotRetired() { ... }

  public PlayerAssert hasName(String name) { ... }

  public PlayerAssert(Player actual) {
    super(actual, PlayerAssert.class);
  }

  public static PlayerAssert assertThat(Player actual) {
    return new PlayerAssert(actual);
  }
}

The generator will also create entry point classes like Assertions, BddAssertions and SoftAssertions/JUnitSoftAssertions to ease accessing each generated *Assert classes.

Let's say for example that the generator has been applied on Player and Game classes, it has then created PlayerAssert and GameAssert classes and an Assertions class looking like:

// the generator selects the base package of classes it generates assertions for 
package org.player;

public class Assertions {

  /**
   * Creates a new instance of <code>{@link GameAssert}</code>.
   *
   * @param actual the actual value.
   * @return the created assertion object.
   */
  public static GameAssert assertThat(Game actual) {
    return new GameAssert(actual);
  }

  /**
   * Creates a new instance of <code>{@link PlayerAssert}</code>.
   *
   * @param actual the actual value.
   * @return the created assertion object.
   */
  public static PlayerAssert assertThat(Player actual) {
    return new PlayerAssert(actual);
  }

  /**
   * Creates a new <code>{@link Assertions}</code>.
   */
  protected Assertions() {
    // empty
  }
}

You now just have to statically import com.myproject.Assertions.assertThat to use custom assertions for Player and Game in your tests.

import static org.player.Assertions.assertThat;
...
assertThat(mj).hasName("Michael Jordan")
              .hasTeam("Chicago Bulls")
              .hasTeamMates("Scottie Pippen", "Tony Kukoc");

The assertion generator uses templates to create assertions, templates are located in the templates directory. There is a template for each type and templates for assert class and entry points.

You can (and are encouraged to) modify the templates to generate additional or different assertions, but be sure to generate code that compiles ! :)

The templates contain variables describing the properties, fields and classes for which assertions are generated, these variables are replaced by the actual values read for each class we generate assertions for.

Let's see how it works with the template used to generate hasName(String name) assertion for Player.

has_assertion_template.txt :

/**
 * Verifies that the actual ${class_to_assert}'s ${property} is equal to the given one.
 * @param ${property_safe} the ${property} to compare the actual ${class_to_assert}'s ${property} to.
 * @return this assertion object.
 * @throws AssertionError - if actual ${class_to_assert}'s ${property} is not equal to the given one.${throws_javadoc}
 */
public ${self_type} has${Property}(${propertyType} ${property_safe}) ${throws}{
  // check that actual ${class_to_assert} we want to make assertions on is not null.
  isNotNull();

  // overrides the default error message with a more explicit one
  String assertjErrorMessage = "\nExpecting ${property} of:\n  <%s>\nto be:\n  <%s>\nbut was:\n  <%s>";
  
  // null safe check
  ${propertyType} actual${Property} = actual.get${Property}();
  if (!Objects.areEqual(actual${Property}, ${property_safe})) {
    failWithMessage(assertjErrorMessage, actual, ${property_safe}, actual${Property});
  }

  // return the current assertion for method chaining
  return ${myself};
}

Variables used to generate hasName(String name) assertion :

Variable Usage Example
${property} property/field we generate an assertion for name
${propertyType} The type of the property/field we generate an assertion for String
${Property} property/field we generate an assertion for, with a capital letter Name
${property_safe} ${property} if not equal to a reserved java keyword, expected${Property} otherwise name
${throws} the exceptions thrown by the property getter (if any) -
${throws_javadoc} javadoc of the exceptions thrown by the property getter (if any) -
${class_to_assert} Class we are generating assertion for Player
${self_type} the assertion class name PlayerAssert
${myself} represents the assertion class instance used to perform assertions this


And finally here's the generated assertion :

/**
 * Verifies that the actual Player's name is equal to the given one.
 * @param name the name to compare the actual Player's name to.
 * @return this assertion object.
 * @throws AssertionError - if the actual Player's name is not equal to the given one.
 */
public PlayerAssert hasName(String name) {
  // check that actual Player we want to make assertions on is not null.
  isNotNull();

  // overrides the default error message with a more explicit one
  String assertjErrorMessage = "\nExpecting name of:\n  <%s>\nto be:\n  <%s>\nbut was:\n  <%s>";
  
  // null safe check
  String actualName = actual.getName();
  if (!Objects.areEqual(actualName, name)) {
    failWithMessage(assertjErrorMessage, actual, name, actualName);
  }

  // return the current assertion for method chaining
  return this;
}

Here's the list of template files and what they are used for.

Assertions method templates
Assertion method template file Usage Example
has_assertion_template.txt assertion for Object (used unless a more specific template is found) hasName("Joe")
is_assertion_template.txt assertion for boolean isRookie()
is_wrapper_assertion_template.txt assertion for Boolean isRookie()
has_assertion_template_for_char.txt assertion for char primitive type hasGender('F')
has_assertion_template_for_character.txt assertion for Character hasGender('F')
has_assertion_template_for_whole_number.txt assertion for int, long, short and byte hasAge(23)
has_assertion_template_for_whole_number_wrapper.txt assertion for Integer, Long, Short and Byte hasAge(23)
has_assertion_template_for_real_number.txt assertion for float and double hasHeight(1.87)
has_assertion_template_for_real_number_wrapper.txt assertion for Float and Double hasHeight(1.87)
has_elements_assertion_template_for_array.txt assertion for array. hasTeamMates("mj")
has_elements_assertion_template_for_iterable.txt assertion for Iterable. hasTeamMates("mj")
Assertions class templates
Assertion class template file Usage
custom_assertion_class_template.txt assert class skeleton
custom_abstract_assertion_class_template.txt base assertion class in in hierarchical assertion
custom_hierarchical_assertion_class_template.txt concrete assertion class in in hierarchical assertion
Assertions entry point templates
Entry point class/methods template file Usage
standard_assertions_entry_point_class_template.txt Assertions class skeleton
standard_assertion_entry_point_method_template.txt template for assertThat method in entry point class like Assertions
bdd_assertions_entry_point_class_template.txt BddAssertions class skeleton
bdd_assertion_entry_point_method_template.txt template for then method in BddAssertions entry point class
soft_assertions_entry_point_class_template.txt SoftAssertions class skeleton
soft_assertion_entry_point_method_template.txt template for "soft" assertThat method in SoftAssertions entry point class
junit_soft_assertions_entry_point_class_template.txt JUnitSoftAssertions class skeleton

Variables used in the assertions templates:

Common variables (assertion level)
${property} property/field we generate an assertion for
${propertyType} The type of the property/field we generate an assertion for
${Property} property/field we generate an assertion for, with a capital letter
${property_safe} ${property} if not equal to a reserved java keyword, expected${Property} otherwise
${throws} the exceptions thrown by the property getter (if any)
${throws_javadoc} javadoc of the exceptions thrown by the property getter (if any)
${class_to_assert} Class we are generating assertion for
${self_type} the assertion class name
${myself} represents the assertion class instance used to perform assertions
Variables specific to boolean/predicate assertions
${predicate} predicate assertion method name. ex: isRookie()
${neg_predicate} negative predicate assertion method name. ex: isNotRookie()
${predicate_for_error_message_part1} used to build the first part of a predicate error message.
${predicate_for_error_message_part2} used to build the second part of a predicate error message.
${negative_predicate_for_error_message_part1} used to build the first part of a negative predicate error message.
${negative_predicate_for_error_message_part2} used to build the second part of a negative predicate error message.
${predicate_for_javadoc} predicate assertion method javadoc
${negative_predicate_for_javadoc} negative predicate assertion method javadoc
Variables specific to array assertions
${elementType} the element type of the array property. ex: String for a String[] property
Variables specific to assertion class
${custom_assertion_class} the assertion class name. ex: PlayerAssert
${super_assertion_class} used for the super class in hierarchical assertions.
${imports} imports off the current generated assertion class.
${package} assertion class package (same as the class we generate assertion for).
Variables specific to assertion entry points classes
${all_assertions_entry_points} all the generated entry points. ex: assertThat for Assertions or then for BddAssertions

This quickstart guide is for non maven users, if you are a maven user, you should use the assertions generator maven plugin.

Get the AssertJ Assertions Generator archive (either for unix or windows) and extract it, its structure is :

assertion-generator/
  |-- lib/
  |-- templates/
  |-- generate-assertions script (.bat or .sh)

First, put in lib/ the jars containing the classes you want to generate assertions for, then run the script with either the classes or the packages containing the classes you want to generate assertions for.

Example : generating assertions for TolkienCharacter class :

generate-assertions.sh org.assertj.examples.data.TolkienCharacter

Example : generating assertions for all classes in org.assertj.examples.data :

generate-assertions.sh org.assertj.examples.data

Your assertions classes have been generated ! You can find them in the current directory.

You can change what is generated by modifying the templates used for assertions creation (have a look at templates directory)

Release date : 2015-08-01

Thanks to Alexander Bischof for his contributions to this release.

  • Uses java 7.
  • Define different assertion templates for whole number, real numbers and char properties.
  • Document how assertion templates are used to generate assertions.
  • Generate both hasValue(v) and hasValueCloseTo(v, delta) for real numbers properties.
  • Fix : Predicate assertion was badly generated when boolean property contained 'is'.
  • Fix : Predicate assertion is now generated for Boolean property not starting by 'is'.

Release date : 2015-04-11

Huge thanks to Jeremy Krieg for his contributions to this release.

  • Generate hasOnly and doesNotHave assertions for array/iterable properties.
  • Better error messages.
  • Sanitise property names when they clash with Java keywords. (Fr Jeremy Krieg)
  • Skip generation of field assertion if it would cause a name clash with a property assertion. (Fr Jeremy Krieg)
  • Handle other boolean predicate forms than is like was, can, will, shouldBe. (Fr Jeremy Krieg)
  • Generated iterable/array assertions did not to honour the description set with as() method when given iterable/array was null.

Release date : 2014-11-02

  • Generate JUnitSoftAssertions.
  • Fix potential import clash by using fully qualified class names (except for AssertJ classes).
  • Fix class cast exception when an overriden getter returns a generic type.

Release date : 2014-08-31

  • Fixes bad generated code in hasNoXXX assertion for iterable property.
  • Fixes bad generated code in contains assertion for iterable property with upper bound wildcard (? extends).
  • Fix to generate assertion for classes having '$' character in class name.
  • Fix fenerated assertion for public boolean field.
  • Use fully qualified name class instead of import in Assertions entry point classes.

Release date : 2014-08-17

  • Correctly resolve generic return types.
  • Use Guava ClassPath instead of org.reflections.

Release date : 2014-08-03

Big thanks to Fr Jeremy Krieg for his work on this release.

  • Generate assertions using offset for double and float types.
  • Allow to generate assertion classes that don't hide subclasses assertions after using an assertion from a super class. (Fr Jeremy Krieg)
  • Generate assertions for public fields.
  • Prepend enclosing class name to inner class assertion name to avoid clash when several inner classes have the same name.
  • Don't generate classes with unused import. (Fr Jeremy Krieg)
  • Generated javadoc improvements. (Fr Jeremy Krieg)
  • Allow to specify where to generate Assertions entry point classes. (floppywaste)
  • Generate a BDD style entry point class BddAssertions replacing assertThat methods by then.
  • Generate a SoftAssertions entry point class to collect all assertion errors instead of stopping at the first one.

Release date : 2013-12-08

  • To ease using generated assertions, generate an entry point class Assertions providing assertThat methods giving access to each generated *Assert classes.
  • Don't generate hasDeclaringClass assertion for Enum.
  • In generated method assertions, rename errorMessage local variable to assertjErrorMessage to avoid collision when object under test has an errorMessage property. (William Delanoue)

Release date : 2013-09-15

Big thanks to Fabien Duminy, he has done most of the work of this release !

  • Generated assertions use null safe equals for non primtive types.
  • Add exceptions to assertion method signature if underlying getter of class to assert throws some. (Fabien Duminy)
  • Generate assertions for nested/inner classes. (Fabien Duminy)
  • Fix error message displaying unrelevant property value when getter of class to assert doesn't return the same value on successive calls. (Fabien Duminy)

Release date : 2013-03-26

It's the first release after Fest fork, generated assertions are cleaner.

If you have any questions, please use AssertJ google group.

AssertJ assertions generator is hosted on github : https://github.com/joel-costigliola/assertj-assertions-generator.

Please report bugs or missing features in AssertJ assertions generator issue tracker.

Thanks for your interest ! Please check our contributor's guidelines.

Special thanks to AssertJ assertions generator contributors:

  • Fabien Duminy
  • William Delanoue
  • floppywaste
  • Fr Jeremy Krieg