Unit Test with AssertJ in java
assertThat() with AssertJ Assertions
In this tutorial, we’ll learn how to write efficient unit test cases in Java using AssertJ assertThat()
assertions.
AssertJ
AssertJ is a Java library that provides a rich set of assertions similar to Hamcrest, which are very fluent to test the conditions on String, Number, Date, Time, Object, Collections, URI, File, etc.
AssertJ also supports soft assertions and writing custom messages in assertions. We will learn all these using examples.
You write unit tests with AssertJ using assertThat()
statement followed by one or more assertions applicable to that class type.
Setup AssertJ
Import the required assertj-core dependency for Java using Maven (pom.xml) or Gradle (build.gradle), whichever you are using:-
<!-- add dependency in pom.xml -->
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<!-- use 2.9.1 for Java 7 projects -->
<version>3.23.1</version>
<scope>test</scope>
</dependency>
// add dependency in build.gradle
dependencies {
testImplementation 'org.assertj:assertj-core:3.23.1'
}
Import AssertJ
Once you add the AssertJ dependency, you can import static assertThat
method in the unit test class like this:-
import static org.assertj.core.api.Assertions.*;
We are ready to write unit test cases with AssertJ.
Using AssertJ Assertions
AssertJ provides assertions for most of the data types in Java e.g. Text (String), Number (Integer, Double, BigDecimal), Collection (List, Array, Set, Map), File, etc. See the complete list of assertions available in AssertJ core package
String assertions
AssertJ provides a variety of fluent assertions for String. Let’s look at them:-
String nullString = null;
// Assert that a String is not null
assertThat("notnull").isNotNull();
// Assert that a String is null or empty
assertThat(nullString).isNullOrEmpty();
assertThat("").isNullOrEmpty();
// Assert that a String is empty
assertThat("").isEmpty();
// Assert that a String is blank i.e. null, empty, or consists of one or more whitespace characters
assertThat(nullString).isBlank();
assertThat("").isBlank();
assertThat(" ").isBlank();
assertThat(" \t ").isBlank();
// Assert that a String has given size
assertThat("abc").hasSize(3);
assertThat("abc").hasSizeLessThan(4);
assertThat("abc").hasSizeLessThanOrEqualTo(4);
assertThat("abc").hasSizeGreaterThan(2);
assertThat("abc").hasSizeGreaterThanOrEqualTo(2);
// Assert that a String has same size as other String, Array or List
assertThat("abc").hasSameSizeAs("def");
assertThat("abc").hasSameSizeAs(new char[] { 'd', 'e', 'f' });
assertThat("abc").hasSameSizeAs(Arrays.asList(1, 2, 3));
// Assert that a String has given number of lines
String multiLine = "First line\n" +
"Last line";
assertThat(multiLine).hasLineCount(2);
// Assert that two Strings are equal
assertThat("foo").isEqualTo("foo");
// Assert that two Strings are equal ignoring case
assertThat("FOO").isEqualToIgnoringCase("foo");
// Assert that a String is a number
assertThat("10").containsOnlyDigits();
// Assert that a String contains the given one or more Substrings
assertThat("Gandalf the grey").contains("alf");
assertThat("Gandalf the grey").contains("alf", "grey");
assertThat("Gandalf the grey").contains(Arrays.asList("alf", "grey"));
assertThat("Gandalf the grey").containsIgnoringCase("gandalf");
// Assert that a String starts with given Substring
assertThat("Lord of the Rings").startsWith("Lord");
assertThat("Lord of the Rings").startsWithIgnoringCase("lord");
// Assert that a String ends with given Substring
assertThat("Lord of the Rings").endsWith("Rings");
assertThat("Lord of the Rings").endsWithIgnoringCase("rings");
// Assert that a String is of given case
assertThat("abc").isLowerCase();
assertThat("camelCase").isMixedCase();
assertThat("ABC").isUpperCase();
For the complete list of String’s assertions, see AssertJ’s documentation AbstractCharSequenceAssert
Integer, Long, Double, Float, and BigDecimal assertions
AssertJ provides a variety of fluent assertions for Numbers.
-
Test some common conditions on Integer, Long, Double, Float and BigDecimals:-
// Assert that two Numbers are equal assertThat(1).isEqualTo(1); // Assert that a Number is 0 assertThat(0).isZero(); ssertThat(0.0).isZero(); assertThat(BigDecimal.ZERO).isZero(); // Assert that a Number is not 0 assertThat(42).isNotZero(); assertThat(3.14).isNotZero(); assertThat(BigDecimal.ONE).isNotZero(); // Assert that a Number is positive assertThat(42).isPositive(); assertThat(3.14).isPositive(); // Assert that a Number is negative assertThat(-42).isNegative(); assertThat(-3.12).isNegative(); // Assert that a Number is even assertThat(12).isEven(); assertThat(-46).isEven(); // Assert that a Number is odd assertThat(3).isOdd(); assertThat(-17).isOdd(); // Assert that a number is less than (or equal to) given number assertThat(1).isLessThan(2); assertThat(-2).isLessThan(-1); assertThat(1).isLessThanOrEqualTo(1); // Assert that a number is greater than (or equal to) given number assertThat(1).isGreaterThan(0); assertThat(-1).isGreaterThan(-2); assertThat(1).isGreaterThanOrEqualTo(1); // Assert that a number is within given range (inclusive) assertThat(1).isBetween(1, 3); // Assert that a number is within given range (exclusive) assertThat(2).isStrictlyBetween(1, 3);
-
Compare two Double values with given precision:-
assertThat(3.141592653589793238).isEqualTo(3.14, withPrecision(0.01)); // pass
Here
withPrecision(0.01)
means to check the equality upto 2 decimal places
For the complete list of Number’s assertions, see AssertJ’s documentation AbstractIntegerAssert, AbstractLongAssert, AbstractDoubleAssert, AbstractFloatAssert, and AbstractBigDecimalAssert
LocalDate, LocalTime, and LocalDateTime assertions
AssertJ provides a variety of assertions to check the date, time, or date-time. Let’s look at them:-
-
Assert that a LocalDate is not null and is today’s date:-
assertThat(LocalDate.now()).isNotNull().isToday();
-
Assert that a LocalDate has given Year, Month, and Day:-
@Test public void givenLocalDate_whenHasGivenYearMonthAndDay_thenPass() { //ISO_LOCAL_DATE YYYY-MM-DD LocalDate date = LocalDate.parse("2020-01-15"); assertThat(date).isEqualTo("2020-01-15"); assertThat(date).hasYear(2020); assertThat(date).hasMonth(Month.JANUARY); assertThat(date).hasMonthValue(1); assertThat(date).hasDayOfMonth(15); }
-
Assert that a LocalDate is before or after the given LocalDate:-
@Test public void givenLocalDate_whenBeforeOrAfterGivenDate_thenPass(){ LocalDate date = LocalDate.parse("2020-01-15"); LocalDate nextDate = LocalDate.parse("2020-01-16"); assertThat(date).isNotEqualTo(nextDate); assertThat(date).isBefore(nextDate); assertThat(date).isBeforeOrEqualTo(nextDate); assertThat(nextDate).isAfter(date); assertThat(nextDate).isAfterOrEqualTo(date); }
-
Assert that a LocalDate is in the given Date range (inclusive):-
@Test public void givenLocalDate_whenInGivenDateRangeInclusive_thenPass() { LocalDate localDate = LocalDate.now(); assertThat(localDate).isBetween(localDate.minusDays(1), localDate.plusDays(1)) .isBetween(localDate, localDate.plusDays(1)) .isBetween(localDate.minusDays(1), localDate) .isBetween(localDate, localDate); LocalDate firstOfJanuary2000 = LocalDate.parse("2000-01-01"); assertThat(firstOfJanuary2000).isBetween("1999-01-01", "2001-01-01") .isBetween("2000-01-01", "2001-01-01") .isBetween("1999-01-01", "2000-01-01") .isBetween("2000-01-01", "2000-01-01"); }
The start date and end date in
.isBetween(startDate, endDate)
are included in the range check. -
Assert that a LocalDate is in the given Date range (exclusive):-
@Test public void givenLocalDate_whenInGivenDateRangeExclusive_thenPass() { LocalDate localDate = LocalDate.now(); assertThat(localDate).isStrictlyBetween(localDate.minusDays(1), localDate.plusDays(1)); LocalDate firstOfJanuary2000 = LocalDate.parse("2000-01-01"); assertThat(firstOfJanuary2000).isStrictlyBetween("1999-01-01", "2001-01-01"); }
The start date and end date in
.isStrictlyBetween(startDate, endDate)
are excluded from the range check. -
Assert that a LocalTime matches conditions:-
@Test public void givenLocalTime_whenMatchesConditions_thenPass() { // ISO_LOCAL_TIME HH::MM::SS LocalTime localTime = LocalTime.parse("10:00:00"); assertThat(localTime).isNotNull().isEqualTo("10:00:00"); assertThat(localTime).isBefore("14:00:00"); assertThat(localTime).isAfter("09:00:00"); }
-
Assert that a LocalDateTime matches conditions:-
@Test public void givenLocalDateTime_whenMatchesConditions_thenPass() { // ISO_LOCAL_DATE_TIME YYYY-MM-DDTHH:MM:SS LocalDateTime localDateTime = LocalDateTime.parse("2000-01-01T23:59:59"); assertThat(localDateTime).isNotNull().isEqualTo("2000-01-01T23:59:59"); assertThat(localDateTime).isBefore("2000-01-02T00:00:00"); assertThat(localDateTime).isAfter("1999-01-01T00:00:00"); }
Checkout AssertJ’s documentation for the full list of Date and Time assertions - AbstractLocalDateAssert, AbstractLocalTimeAssert, and AbstractLocalDateTimeAssert
Object assertions
- Assert that two objects are equal:-
@Test public void givenTwoObjects_whenEquals_thenPass() { User user1 = User.builder().firstName("Adam").build(); User user2 = User.builder().firstName("Adam").build(); assertThat(user1).isEqualTo(user2); }
- Assert that an Object is null:-
@Test public void givenObject_whenNull_thenPass() { User user = null; assertThat(user).isNull(); }
- Assert that an Object is the same as the given instance
@Test public void givenTwoObjects_whenSameInstance_thenPass() { User user = User.builder().firstName("Adam").build(); assertThat(user).isSameAs(user); }
- Assert that two Objects have the same property values:-
@Test public void givenTwoObjects_whenSamePropertyValues_thenPass() { User user1 = User.builder().firstName("Adam").age(22).isPremiumUser(true).build(); User user2 = User.builder().firstName("Adam").age(22).isPremiumUser(true).build(); assertThat(user1).usingRecursiveComparison().isEqualTo(user2); }
- Assert that two Objects have the same property values ignoring one or more given properties:-
@Test public void givenTwoObjects_whenSamePropertyValuesExcludingIgnoredProps_thenPass() { User user1 = User.builder().firstName("Adam").age(22).isPremiumUser(true).build(); User user2 = User.builder().firstName("Adam").age(18).isPremiumUser(false).build(); assertThat(user1).usingRecursiveComparison() .ignoringFields("age", "isPremiumUser").isEqualTo(user2); }
- Assert that two Objects have the same property values ignoring one or more properties with null values:-
@Test public void givenTwoObjects_whenSamePropertyValuesExcludingNullProps_thenPass() { User user1 = User.builder().firstName("Adam").age(22).isPremiumUser(true).build(); User user2 = User.builder().firstName("Adam").age(null).isPremiumUser(null).build(); assertThat(user1).usingRecursiveComparison() .ignoringExpectedNullFields() .isEqualTo(user2); }
- Assert that an Object has all the properties with non-null values:-
@Test public void givenObject_whenHasNoNullProperties_thenPass() { User user = User.builder().firstName("Adam").age(22).isPremiumUser(true).build(); assertThat(user).hasNoNullFieldsOrProperties(); }
- Assert that an Object has all the properties with null values:-
@Test public void givenObject_whenHasAllNullProperties_thenPass() { User user = User.builder().firstName(null).age(null).isPremiumUser(null).build(); assertThat(user).hasAllNullFieldsOrProperties(); }
- Assert that an Object has properties with the given names:-
@Test public void givenObject_whenHasGivenProperties_thenPass() { User user = User.builder().build(); assertThat(user).hasFieldOrProperty("firstName"); assertThat(user).hasFieldOrProperty("age"); assertThat(user).hasFieldOrProperty("isPremiumUser"); }
- Assert that an Object has properties with the given names and values:-
@Test public void givenObject_whenHasPropertyWithGivenNameAndValue_thenPass() { User user = User.builder().firstName("Adam").age(22).isPremiumUser(true).build(); assertThat(user).hasFieldOrPropertyWithValue("firstName", "Adam"); assertThat(user).hasFieldOrPropertyWithValue("age", 22); assertThat(user).hasFieldOrPropertyWithValue("isPremiumUser", true); assertThat(user).extracting("firstName").isEqualTo("Adam"); assertThat(user).extracting("age").isEqualTo(22); assertThat(user).extracting("isPremiumUser").isEqualTo(true); assertThat(user).extracting("firstName", "age", "isPremiumUser").containsExactly("Adam", 22, true); }
For the complete list of Object’s assertions, see AssertJ’s documentation AbstractObjectAssert
List/Array assertions
AssertJ provides similar assertions for List and Array. Let’s look at the example where we are testing multiple conditions on List by chaining assertions one after another:-
@Test
public void givenList_whenMatchesConditions_thenPass(){
List<String> list = Arrays.asList("lord", "of", "the", "rings");
assertThat(list)
.isNotNull()
.isNotEmpty()
.hasSize(4)
.startsWith("lord")
.contains("of")
.contains("the", atIndex(2))
.endsWith("rings")
.containsSequence("of", "the");
assertThat("lord").isIn(list);
}
Checkout AssertJ’s documentation for the full list of List’s assertions - AbstractListAssert
Map assertions
AsssertJ provides assertion for Map to check keys, values, and entries. Let’s look at them:-
- Assert that a Map is null or empty:-
assertThat(new HashMap()).isNullOrEmpty(); assertThat(new HashMap()).isEmpty();
- Assert that a Map contains the given Key, Value, and Entry using multiple chained assertions:-
@Test public void givenMap_whenMatchesConditions_thenPass(){ Map<String, String> myMap = new HashMap<>(); myMap.put("myKey1", "myValue1"); myMap.put("myKey2", "myValue2"); assertThat(myMap) .isNotNull() .isNotEmpty() .hasSize(2) .containsKey("myKey1") .containsValue("myValue2") .containsEntry("myKey1", "myValue1") .contains(entry("myKey2", "myValue2")); }
Checkout AssertJ’s documentation for the full list of Map’s assertions - AbstractMapAssert
URI assertions
Let’s look at various assertions for http, https, mailto, and file URLs:-
@Test
public void givenURI_whenMatchesConditions_thenPass() throws URISyntaxException {
assertThat(new URI("http://localhost:8080"))
.hasScheme("http")
.hasHost("localhost")
.hasPort(8080)
.hasPath("")
.hasNoQuery()
.hasNoParameters();
assertThat(new URI("https://reqres.in/api/users?name=adam&page=1"))
.hasScheme("https")
.hasHost("reqres.in")
.hasNoPort()
.hasPath("/api/users")
.hasQuery("name=adam&page=1")
.hasParameter("name")
.hasParameter("page", "1");
assertThat(new URI("mailto:java-net@java.sun.com"))
.hasScheme("mailto")
.hasNoHost()
.hasNoPort()
.hasNoPath();
assertThat(new URI("file:///home/user/Documents/hello-world.txt"))
.hasScheme("file")
.hasNoPort()
.hasNoHost()
.hasPath("/home/user/Documents/hello-world.txt");
}
Checkout AssertJ’s documentation for the full list of Java URI’s assertions - AbstractUriAssert
File assertions
AssertJ file provides a variety of assertions to check the File and Directory properties, size, path and it’s content. Let’s look at some examples:-
@Test
public void givenFile_whenMatchesConditions_thenPass() throws IOException {
File tmpFile = File.createTempFile("tmp", "txt");
File tmpDir = Files.createTempDirectory("tmpDir").toFile();
assertThat(tmpFile)
.exists()
.isFile()
.isReadable()
.isWritable()
.hasSize(0);
assertThat(tmpDir)
.exists()
.isDirectory();
}
AssertJ has a lot more useful Java File and Directory assertions, check them out - AbstractFileAssert and AbstractFileSizeAssert
Soft assertions
AssertJ is hard assertion by default
AssertJ assertions are hard assertions by default, which means when you have multiple assertions in the test case and if one of them fails, it throws an exception and stops the execution there. Assertions after the failed assertion will not be executed. Let’s look at the below example of Hard Assertion:-
import static org.assertj.core.api.Assertions.*;
@Test
public void whenTestFail_hardAssert_stopExecution(){
String text = "abc";
assertThat(text).hasSize(3); // pass
assertThat(text).contains("z"); // fail - stop execution
assertThat(text).startsWith("a"); // not executed
assertThat(text).isEqualTo("def"); // not executed
}
An AssertionError is thrown upon execution like this:-
java.lang.AssertionError:
Expecting actual:
"abc"
to contain:
"z"
at com.example.assertion.AssertJAssertThatTests.whenTestFail_hardAssert_stopExecution(AssertJAssertThatTests.java:463)
AssertJ soft assertion to the rescue
There are cases where we want to execute all the assertions in a test case regardless of failure and generate a report of total passed and failed assertions. This is known as Soft Assertion. Luckily AssertJ provides Assertions.SoftAssertions
for this. Let’s look at the below example of Soft Assertion:-
import static org.assertj.core.api.Assertions.*;
@Test
public void whenTestFail_softAssert_continueExecution(){
String text = "abc";
SoftAssertions softly = new SoftAssertions();
softly.assertThat(text).hasSize(3); // pass
softly.assertThat(text).contains("z"); // fail - continue execution
softly.assertThat(text).startsWith("a"); // pass
softly.assertThat(text).isEqualTo("def"); // fail
softly.assertAll(); // must specify
}
Remember to specify softly.assertAll()
after all your assertions, which tells AssertJ to execute all assertions regardless of failure.
You can also use the static method SoftAssertions.assertSoftly
. The softly.assertAll()
method will be called automatically after the lambda function completes. Check out the example below:-
@Test
public void whenTestFail_softAssert_continueExecution_lambda(){
String text = "abc";
SoftAssertions.assertSoftly(softly -> {
softly.assertThat(text).hasSize(3); // pass
softly.assertThat(text).contains("z"); // fail - continue execution
softly.assertThat(text).startsWith("a"); // pass
softly.assertThat(text).isEqualTo("def"); // fail
});
}
Here is the sample test report after execution:-
org.assertj.core.error.AssertJMultipleFailuresError:
Multiple Failures (2 failures)
-- failure 1 --
Expecting actual:
"abc"
to contain:
"z"
at AssertJAssertThatTests.whenTestFail_softAssert_continueExecution(AssertJAssertThatTests.java:474)
-- failure 2 --
expected: "def"
but was: "abc"
at AssertJAssertThatTests.whenTestFail_softAssert_continueExecution(AssertJAssertThatTests.java:476)
Custom Message in assertion
You can also add a custom message in assertion using short-named as()
method.
assertThat(object).as(customMessage).assertion...
Important note: You must call as()
method before any actual assertion - otherwise it will not work, as assertion will fire first.
Let’s look at the example:-
@Test
public void givenObject_testAgeWithCustomMessage(){
User user = new User("Joe", 22, true);
assertThat(user.getAge()).as("check %s's age", user.getFirstName()).isEqualTo(18);
}
It logs the custom message in case of assertion failure, which is more readable:-
org.opentest4j.AssertionFailedError: [check Joe's age]
expected: 18
but was: 22
That’s all about AssertJ assertions. Thanks for Reading!