Guide to AssertJ Library in Java

Introduction

AssertJ is a fluent assertion library for Java that provides a rich set of assertions and a fluent API to improve the readability and maintainability of tests. AssertJ can be used with any testing framework like JUnit or TestNG. This guide will cover the installation, basic usage, advanced features, and complex examples using AssertJ, including detailed explanations of all important assertions.

Installation

To use AssertJ, add the following dependency to your pom.xml if you're using Maven:

<dependency>
    <groupId>org.assertj</groupId>
    <artifactId>assertj-core</artifactId>
    <version>3.24.2</version> <!-- or the latest version -->
    <scope>test</scope>
</dependency>

For Gradle:

dependencies {
    testImplementation 'org.assertj:assertj-core:3.24.2' // or the latest version
}

Basic Usage

AssertJ with JUnit

Example: Basic Assertions

import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;

public class BasicAssertionsTest {
    @Test
    public void testBasicAssertions() {
        String name = "Amit";
        int age = 30;

        assertThat(name).isEqualTo("Amit");
        assertThat(age).isGreaterThan(20).isLessThan(40).isEqualTo(30);
    }
}

Output

Test passed

Important AssertJ Assertions

Basic Assertions

isEqualTo()

Asserts that the actual value is equal to the expected value.

@Test
public void testIsEqualTo() {
    String name = "Anil";
    assertThat(name).isEqualTo("Anil");
}

isNotEqualTo()

Asserts that the actual value is not equal to the expected value.

@Test
public void testIsNotEqualTo() {
    String name = "Anil";
    assertThat(name).isNotEqualTo("Vikas");
}

String Assertions

contains()

Asserts that the actual string contains the given sequence.

@Test
public void testContains() {
    String sentence = "Anil is a software engineer";
    assertThat(sentence).contains("software");
}

doesNotContain()

Asserts that the actual string does not contain the given sequence.

@Test
public void testDoesNotContain() {
    String sentence = "Anil is a software engineer";
    assertThat(sentence).doesNotContain("doctor");
}

startsWith()

Asserts that the actual string starts with the given prefix.

@Test
public void testStartsWith() {
    String sentence = "Anil is a software engineer";
    assertThat(sentence).startsWith("Anil");
}

endsWith()

Asserts that the actual string ends with the given suffix.

@Test
public void testEndsWith() {
    String sentence = "Anil is a software engineer";
    assertThat(sentence).endsWith("engineer");
}

isEmpty()

Asserts that the actual string is empty.

@Test
public void testIsEmpty() {
    String emptyString = "";
    assertThat(emptyString).isEmpty();
}

Collection Assertions

hasSize()

Asserts that the actual collection has the given size.

@Test
public void testHasSize() {
    List<String> names = List.of("Arjun", "Priya", "Lakshmi");
    assertThat(names).hasSize(3);
}

contains()

Asserts that the actual collection contains the given values.

@Test
public void testContains() {
    List<String> names = List.of("Arjun", "Priya", "Lakshmi");
    assertThat(names).contains("Priya", "Lakshmi");
}

doesNotContain()

Asserts that the actual collection does not contain the given values.

@Test
public void testDoesNotContain() {
    List<String> names = List.of("Arjun", "Priya", "Lakshmi");
    assertThat(names).doesNotContain("Ravi");
}

containsExactly()

Asserts that the actual collection contains exactly the given values in the given order.

@Test
public void testContainsExactly() {
    List<String> names = List.of("Arjun", "Priya", "Lakshmi");
    assertThat(names).containsExactly("Arjun", "Priya", "Lakshmi");
}

Map Assertions

hasSize()

Asserts that the actual map has the given size.

@Test
public void testHasSize() {
    Map<String, Integer> ageMap = Map.of("Rohit", 28, "Sneha", 25, "Vikas", 35);
    assertThat(ageMap).hasSize(3);
}

containsKeys()

Asserts that the actual map contains the given keys.

@Test
public void testContainsKeys() {
    Map<String, Integer> ageMap = Map.of("Rohit", 28, "Sneha", 25, "Vikas", 35);
    assertThat(ageMap).containsKeys("Rohit", "Sneha");
}

containsValues()

Asserts that the actual map contains the given values.

@Test
public void testContainsValues() {
    Map<String, Integer> ageMap = Map.of("Rohit", 28, "Sneha", 25, "Vikas", 35);
    assertThat(ageMap).containsValues(25, 35);
}

doesNotContainKeys()

Asserts that the actual map does not contain the given keys.

@Test
public void testDoesNotContainKeys() {
    Map<String, Integer> ageMap = Map.of("Rohit", 28, "Sneha", 25, "Vikas", 35);
    assertThat(ageMap).doesNotContainKeys("Amit");
}

doesNotContainValue()

Asserts that the actual map does not contain the given value.

@Test
public void testDoesNotContainValue() {
    Map<String, Integer> ageMap = Map.of("Rohit", 28, "Sneha", 25, "Vikas", 35);
    assertThat(ageMap).doesNotContainValue(40);
}

Object Assertions

isNotNull()

Asserts that the actual object is not null.

@Test
public void testIsNotNull() {
    String name = "Anil";
    assertThat(name).isNotNull();
}

isNull()

Asserts that the actual object is null.

@Test
public void testIsNull() {
    String name = null;
    assertThat(name).isNull();
}

isInstanceOf()

Asserts that the actual object is an instance of the given class.

@Test
public void testIsInstanceOf() {
    String name = "Anil";
    assertThat(name).isInstanceOf(String.class);
}

Boolean Assertions

isTrue()

Asserts that the actual boolean value is true.

@Test
public void testIsTrue() {
    boolean isActive = true;
    assertThat(isActive).isTrue();
}

isFalse()

Asserts that the actual boolean value is false.

@Test
public void testIsFalse() {
    boolean isActive = false;
    assertThat(isActive).isFalse();
}

Numeric Assertions

isGreaterThan()

Asserts that the actual number is greater than the given number.

@Test
public void testIsGreaterThan() {
    int age = 30;
    assertThat(age).isGreaterThan(20);
}

isLessThan()

Asserts that the actual number is less than the given number.

@Test
public void testIsLessThan() {
    int age = 30;
    assertThat(age).isLessThan(40);
}

isBetween()

Asserts that the actual number is between the given start and end values (inclusive).

@Test
public void testIsBetween() {
    int age = 30;
    assertThat(age).isBetween(20, 40);
}

Date and Time Assertions

isBefore()

Asserts that the actual date is before the given date.

@Test
public void testIsBefore() {
    LocalDate today = LocalDate.now();
    LocalDate tomorrow = today.plusDays(1);
    assertThat(today).isBefore(tomorrow);
}

isAfter()

Asserts that the actual date is after the given date.

@Test
public void testIsAfter() {
    LocalDate today = LocalDate.now();
    LocalDate yesterday = today.minusDays(1);
    assertThat(today).isAfter(yesterday);
}

isEqualTo()

Asserts that the actual date is equal to the given date.

@Test
public void testIsEqualTo() {
    LocalDate today = LocalDate.now();
    assertThat(today).isEqualTo(LocalDate.now());
}

Exception Assertions

isThrownBy()

Asserts that the given exception is thrown by the provided code.

@Test




public void testIsThrownBy() {
    assertThatThrownBy(() -> {
        throw new IllegalArgumentException("Invalid argument");
    }).isInstanceOf(IllegalArgumentException.class)
      .hasMessage("Invalid argument");
}

Soft Assertions

Soft assertions allow multiple assertions to be executed, collecting all failures to be reported at the end.

@Test
public void testSoftAssertions() {
    SoftAssertions softAssertions = new SoftAssertions();

    softAssertions.assertThat("Amit").isEqualTo("Amit");
    softAssertions.assertThat(25).isGreaterThan(20);
    softAssertions.assertThat(false).isTrue();  // This will fail
    softAssertions.assertThat("Lakshmi").isNotEmpty();

    softAssertions.assertAll();  // This will report all failures
}

BDD Assertions

BDD-style assertions using the then syntax for behavior-driven development.

@Test
public void testBddAssertions() {
    String name = "Lakshmi";
    int age = 27;

    then(name).isEqualTo("Lakshmi");
    then(age).isBetween(25, 30);
}

Output

Test passed

Advanced Features

Collection Assertions

AssertJ provides a rich set of assertions for collections.

Example: List Assertions

@Test
public void testListAssertions() {
    List<String> names = List.of("Arjun", "Priya", "Lakshmi");

    assertThat(names)
        .hasSize(3)
        .contains("Priya")
        .doesNotContain("Ravi")
        .startsWith("Arjun")
        .endsWith("Lakshmi");
}

Output

Test passed

Map Assertions

Example: Map Assertions

@Test
public void testMapAssertions() {
    Map<String, Integer> ageMap = Map.of("Rohit", 28, "Sneha", 25, "Vikas", 35);

    assertThat(ageMap)
        .hasSize(3)
        .containsKeys("Rohit", "Sneha")
        .containsValues(25, 35)
        .doesNotContainKeys("Amit")
        .doesNotContainValue(40);
}

Output

Test passed

Custom Assertions

You can create custom assertions by extending AbstractAssert.

Example: Custom Assertion for a User Class

import org.assertj.core.api.AbstractAssert;

public class UserAssert extends AbstractAssert<UserAssert, User> {
    public UserAssert(User user) {
        super(user, UserAssert.class);
    }

    public static UserAssert assertThatUser(User user) {
        return new UserAssert(user);
    }

    public UserAssert hasName(String name) {
        isNotNull();
        if (!actual.getName().equals(name)) {
            failWithMessage("Expected user's name to be %s but was %s", name, actual.getName());
        }
        return this;
    }

    public UserAssert hasAge(int age) {
        isNotNull();
        if (actual.getAge() != age) {
            failWithMessage("Expected user's age to be %d but was %d", age, actual.getAge());
        }
        return this;
    }
}

class User {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

@Test
public void testCustomAssertions() {
    User user = new User("Sita", 22);
    UserAssert.assertThatUser(user).hasName("Sita").hasAge(22);
}

Output

Test passed

Exception Assertions

AssertJ provides a fluent API for asserting exceptions.

Example: Exception Assertions

@Test
public void testExceptionAssertions() {
    assertThatThrownBy(() -> { throw new IllegalArgumentException("Invalid argument"); })
        .isInstanceOf(IllegalArgumentException.class)
        .hasMessage("Invalid argument");

    assertThatExceptionOfType(IllegalArgumentException.class)
        .isThrownBy(() -> { throw new IllegalArgumentException("Invalid argument"); })
        .withMessage("Invalid argument");
}

Output

Test passed

Soft Assertions

Soft assertions allow you to execute multiple assertions and report all failures at the end.

Example: Soft Assertions

@Test
public void testSoftAssertions() {
    SoftAssertions softAssertions = new SoftAssertions();

    softAssertions.assertThat("Ravi").isEqualTo("Ravi");
    softAssertions.assertThat(30).isGreaterThan(20);
    softAssertions.assertThat(true).isFalse(); // This will fail
    softAssertions.assertThat("Amit").isNotEmpty();

    softAssertions.assertAll(); // This will report all failures
}

Output

SoftAssertionsTest.testSoftAssertions: Soft assertion errors:
1) expected:<[fals]e> but was:<[tru]e>

BDD Assertions

AssertJ supports BDD-style assertions using the assertThat syntax.

Example: BDD Assertions

@Test
public void testBddAssertions() {
    String name = "Lakshmi";
    int age = 27;

    then(name).isEqualTo("Lakshmi");
    then(age).isBetween(25, 30);
}

Output

Test passed

Extracting and Filtering

AssertJ provides powerful methods for extracting and filtering collections.

Example: Extracting and Filtering

@Test
public void testExtractingFiltering() {
    List<User> users = List.of(
        new User("Rahul", 25),
        new User("Meera", 30),
        new User("Vijay", 35)
    );

    assertThat(users)
        .extracting("name", "age")
        .contains(tuple("Rahul", 25), tuple("Meera", 30))
        .doesNotContain(tuple("Amit", 40));

    assertThat(users)
        .filteredOn(user -> user.getAge() > 30)
        .containsExactly(new User("Vijay", 35));
}

class User {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return age == user.age && name.equals(user.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

Output

Test passed

Complex Examples

Example: Complex Object Assertions

Let's consider a complex object with nested properties and assert its various attributes.

@Test
public void testComplexObjectAssertions() {
    Address address = new Address("123 Main St", "Chennai", "600001");
    User user = new User("Kiran", 30, address, List.of("Admin", "User"));

    assertThat(user)
        .extracting("name", "age")
        .containsExactly("Kiran", 30);

    assertThat(user.getAddress())
        .extracting("street", "city", "zipCode")
        .containsExactly("123 Main St", "Chennai", "600001");

    assertThat(user.getRoles())
        .contains("Admin", "User")
        .doesNotContain("Guest");
}

class User {
    private String name;
    private int age;
    private Address address;
    private List<String> roles;

    public User(String name, int age, Address address, List<String> roles) {
        this.name = name;
        this.age = age;
        this.address = address;
        this.roles = roles;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public Address getAddress() {
        return address;
    }

    public List<String> getRoles() {
        return roles;
    }
}

class Address {
    private String street;
    private String city;
    private String zipCode;

    public Address(String street, String city, String zipCode) {
        this.street = street;
        this.city = city;
        this.zipCode = zipCode;
    }

    public String getStreet() {
        return street;
    }

    public String getCity() {
        return city;
    }

    public String getZipCode() {
        return zipCode;
    }
}

Output

Test passed

Example: Soft Assertions for Complex Objects

Using soft assertions to verify multiple attributes of complex objects.

@Test
public void testSoftAssertionsComplex() {
    SoftAssertions softAssertions = new SoftAssertions();

    Address address = new Address("456 Park Ave", "Mumbai", "400001");
    User user = new User("Aarti", 28, address, List.of("User", "Editor"));

    softAssertions.assertThat(user.getName()).isEqualTo("Aarti");
    softAssertions.assertThat(user.getAge()).isEqualTo(28);
    softAssertions.assertThat(user.getAddress().getCity()).isEqualTo("Mumbai");
    softAssertions.assertThat(user.getRoles()).contains("User

", "Editor");

    softAssertions.assertAll(); // This will report all failures
}

Output

Test passed

Example: Custom Assertions with Nested Objects

Creating custom assertions for complex nested objects.

public class CustomNestedAssertionsTest {
    @Test
    public void testCustomNestedAssertions() {
        Address address = new Address("789 Hill St", "Pune", "411001");
        User user = new User("Anil", 35, address, List.of("Admin", "User"));

        UserAssert.assertThatUser(user)
            .hasName("Anil")
            .hasAge(35)
            .hasAddress("789 Hill St", "Pune", "411001")
            .hasRoles("Admin", "User");
    }
}

class UserAssert extends AbstractAssert<UserAssert, User> {
    public UserAssert(User user) {
        super(user, UserAssert.class);
    }

    public static UserAssert assertThatUser(User user) {
        return new UserAssert(user);
    }

    public UserAssert hasName(String name) {
        isNotNull();
        if (!actual.getName().equals(name)) {
            failWithMessage("Expected user's name to be %s but was %s", name, actual.getName());
        }
        return this;
    }

    public UserAssert hasAge(int age) {
        isNotNull();
        if (actual.getAge() != age) {
            failWithMessage("Expected user's age to be %d but was %d", age, actual.getAge());
        }
        return this;
    }

    public UserAssert hasAddress(String street, String city, String zipCode) {
        isNotNull();
        Address address = actual.getAddress();
        if (!address.getStreet().equals(street) || !address.getCity().equals(city) || !address.getZipCode().equals(zipCode)) {
            failWithMessage("Expected address to be %s, %s, %s but was %s, %s, %s", street, city, zipCode,
                address.getStreet(), address.getCity(), address.getZipCode());
        }
        return this;
    }

    public UserAssert hasRoles(String... roles) {
        isNotNull();
        assertThat(actual.getRoles()).containsExactly(roles);
        return this;
    }
}

class User {
    private String name;
    private int age;
    private Address address;
    private List<String> roles;

    public User(String name, int age, Address address, List<String> roles) {
        this.name = name;
        this.age = age;
        this.address = address;
        this.roles = roles;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public Address getAddress() {
        return address;
    }

    public List<String> getRoles() {
        return roles;
    }
}

class Address {
    private String street;
    private String city;
    private String zipCode;

    public Address(String street, String city, String zipCode) {
        this.street = street;
        this.city = city;
        this.zipCode = zipCode;
    }

    public String getStreet() {
        return street;
    }

    public String getCity() {
        return city;
    }

    public String getZipCode() {
        return zipCode;
    }
}

Output

Test passed

Conclusion

AssertJ is a powerful and flexible assertion library for Java that improves the readability and maintainability of tests. This tutorial covered the basics of AssertJ, including basic assertions, string assertions, collection assertions, map assertions, object assertions, boolean assertions, numeric assertions, date and time assertions, exception assertions, soft assertions, and BDD assertions. Additionally, we explored complex examples such as custom assertions for nested objects and soft assertions for complex objects. By leveraging AssertJ, you can enhance your testing capabilities and ensure the quality and reliability of your Java applications. For more detailed information and advanced features, refer to the official AssertJ documentation.

Comments