How do I compare objects in JUnit tests?

In JUnit tests, you usually compare objects with assertions, not with ==.

The most common choices are:

  • assertEquals(expected, actual) — compares objects using their equals() method.
  • assertSame(expected, actual) — checks whether both references point to the same object.
  • AssertJ’s assertThat(actual).isEqualTo(expected) — a more fluent alternative.
  • Field-by-field assertions — useful when you only care about some properties.

1. Comparing Objects with assertEquals()

In JUnit 5, use:

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

class PersonTest {

    @Test
    void shouldCompareObjectsUsingEquals() {
        Person expected = new Person("Alice", 30);
        Person actual = new Person("Alice", 30);

        assertEquals(expected, actual);
    }
}

This works only if Person correctly overrides equals().

Example:

import java.util.Objects;

public class Person {
    private final String name;
    private final int age;

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

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }

        if (!(o instanceof Person person)) {
            return false;
        }

        return age == person.age &&
                Objects.equals(name, person.name);
    }

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

Now two different Person instances with the same values are considered equal.

2. Do Not Use == for Value Comparison

This checks whether both variables refer to the same object in memory:

Person p1 = new Person("Alice", 30);
Person p2 = new Person("Alice", 30);

assertEquals(p1, p2); // compares values using equals()

But this would fail:

import static org.junit.jupiter.api.Assertions.assertTrue;

assertTrue(p1 == p2); // false, because they are different objects

Use == only when you intentionally want to check reference identity.

3. Use assertSame() for Reference Comparison

If you want to verify that two references point to the exact same object, use assertSame():

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertSame;

class PersonTest {

    @Test
    void shouldReferToSameObject() {
        Person person = new Person("Alice", 30);

        Person samePerson = person;

        assertSame(person, samePerson);
    }
}

Use assertSame() for identity checks, not regular value comparison.

4. Compare Individual Fields

Sometimes you do not need full object equality. You may only care about specific fields:

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

class PersonTest {

    @Test
    void shouldComparePersonFields() {
        Person actual = new Person("Alice", 30);

        assertEquals("Alice", actual.getName());
        assertEquals(30, actual.getAge());
    }
}

This is useful when:

  • the class does not override equals(),
  • only some fields matter,
  • generated fields like id, timestamps, or audit fields should be ignored.

5. Use AssertJ for More Readable Object Assertions

AssertJ provides fluent assertions:

import org.junit.jupiter.api.Test;

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

class PersonTest {

    @Test
    void shouldCompareObjectsWithAssertJ() {
        Person expected = new Person("Alice", 30);
        Person actual = new Person("Alice", 30);

        assertThat(actual).isEqualTo(expected);
    }
}

You can also compare specific properties:

assertThat(actual)
        .extracting(Person::getName, Person::getAge)
        .containsExactly("Alice", 30);

Or compare objects recursively:

assertThat(actual)
        .usingRecursiveComparison()
        .isEqualTo(expected);

Recursive comparison is helpful when objects contain nested objects and you do not want to rely on every class implementing equals().

6. Comparing Lists of Objects

For lists, assertEquals() also uses equals() on each element:

import org.junit.jupiter.api.Test;

import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;

class PersonListTest {

    @Test
    void shouldCompareListsOfPeople() {
        List<Person> expected = List.of(
                new Person("Alice", 30),
                new Person("Bob", 25)
        );

        List<Person> actual = List.of(
                new Person("Alice", 30),
                new Person("Bob", 25)
        );

        assertEquals(expected, actual);
    }
}

The order must match. If order does not matter, AssertJ is often clearer:

assertThat(actual)
        .containsExactlyInAnyOrderElementsOf(expected);

7. Common Rule of Thumb

Use this:

assertEquals(expected, actual);

when you want to compare object values.

Use this:

assertSame(expected, actual);

when you want to check that both variables refer to the exact same object.

Avoid this for object value comparison:

expected == actual

because it checks identity, not logical equality.

Summary

Goal Recommended Assertion
Compare object values assertEquals(expected, actual)
Compare object references assertSame(expected, actual)
Compare selected fields assertEquals(expectedName, actual.getName())
Compare nested objects without relying on equals() AssertJ usingRecursiveComparison()
Compare lists in order assertEquals(expectedList, actualList)
Compare lists ignoring order AssertJ containsExactlyInAnyOrderElementsOf()

In most JUnit tests, object comparison starts with assertEquals(expected, actual), as long as the class has a proper equals() implementation.

How do I test expected values with assertEquals()?

In JUnit, you use assertEquals() to test whether an actual value matches an expected value.

The basic syntax is:

assertEquals(expectedValue, actualValue);

The first argument is what you expect.
The second argument is what your code actually produced.

Basic Example

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

class CalculatorTest {

    @Test
    void shouldAddTwoNumbers() {
        int result = 2 + 3;

        assertEquals(5, result);
    }
}

In this example:

assertEquals(5, result);

means:

I expect the result to be 5.

If result is 5, the test passes.
If result is anything else, the test fails.

Example with Strings

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

class GreetingTest {

    @Test
    void shouldReturnGreetingMessage() {
        String message = "Hello, Java";

        assertEquals("Hello, Java", message);
    }
}

Using a Failure Message

You can add a custom message that appears when the test fails:

assertEquals(10, result, "The result should be 10");

Example:

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

class MathTest {

    @Test
    void shouldMultiplyNumbers() {
        int result = 4 * 3;

        assertEquals(12, result, "4 multiplied by 3 should be 12");
    }
}

Common Mistake

Be careful with the order:

assertEquals(expected, actual);

Good:

assertEquals(100, total);

Less clear:

assertEquals(total, 100);

JUnit will still compare the values, but failure messages are easier to understand when the expected value comes first.

Example with a Method

Suppose you have this class:

class Calculator {

    int add(int a, int b) {
        return a + b;
    }
}

You can test it like this:

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

class CalculatorTest {

    @Test
    void addShouldReturnSum() {
        Calculator calculator = new Calculator();

        int actual = calculator.add(2, 3);

        assertEquals(5, actual);
    }
}

Summary

Use assertEquals() like this:

assertEquals(expected, actual);

For example:

assertEquals(5, result);
assertEquals("Alice", name);
assertEquals(100.0, price);

assertEquals() is one of the most common JUnit assertions because it clearly checks whether your code returned the value you expected.