skip to content

In JUnit 5's assertEquals, what is the argument order, and why does getting it wrong matter?

level: juniorimportance: must knowfreq 70%

answer

  1. expected first, actual second
  2. swap = correct pass/fail, wrong message
  3. 'expected: <X> but was: <Y>'
  4. same order for arrays/iterables/assertSame
  5. AssertJ assertThat(actual).isEqualTo(expected) avoids the trap

basics

~20 s

The order is assertEquals(expected, actual). The first value is what you expect, the second is what your code produced. Swapping them still passes or fails correctly, but the failure message reads backwards and confuses you.

solid answer

~40 s

JUnit 5's assertEquals takes the expected value first and the actual value second: assertEquals(expected, actual). The same convention applies to assertArrayEquals, assertIterableEquals, and assertSame. The assertion itself is symmetric, so a swapped call still passes when values match and fails when they differ. The danger is only in the failure message: JUnit prints 'expected: <X> but was: <Y>'. If you swap the arguments, the message labels your real result as 'expected' and your literal as 'actual', which sends you debugging in the wrong direction. Because the compiler cannot catch this, teams often add an assertion library like AssertJ (assertThat(actual).isEqualTo(expected)) whose fluent API makes the role of each value unambiguous and removes the ordering trap entirely.

go deeper

for a junior

State the order plainly: assertEquals(expected, actual), first is your expectation, second is the code's result.

for a middle

Explain that the call is symmetric for pass/fail but the failure MESSAGE is what breaks when swapped, and that the convention spans assertArrayEquals/assertIterableEquals/assertSame.

for a senior

Note the compiler can't enforce roles, recommend AssertJ for unambiguous reads, and connect clear messages to faster debugging in CI.

for a principal

Frame it as a team-wide readability/diagnostics standard: pick one assertion style, enforce via lint/review, and value failure-message quality as part of test maintainability.

## What an assertion is A **unit test** is a small program that runs a piece of your code and checks the result is what you intended. The check itself is performed by an **assertion**: a method that throws an error (failing the test) if a condition is not met, and does nothing (the test continues) if it is. **JUnit 5** (package `org.junit.jupiter.api`) is the standard testing framework for Java; its assertion methods live in the class `org.junit.jupiter.api.Assertions`. ## assertEquals and its signature The most common assertion is `assertEquals`. Its signature is: ``` assertEquals(expected, actual) ``` - **expected** — the value you, the test author, believe is correct. Usually a literal you typed (e.g. `5`, `"hello"`). - **actual** — the value your production code actually returned when run. JUnit compares the two using `.equals()` (or `==` for primitives) and the test passes when they are equal. ## Why order seems not to matter — but does Equality is **symmetric**: `a.equals(b)` is true exactly when `b.equals(a)` is true. So `assertEquals(5, total)` and `assertEquals(total, 5)` have the *same pass/fail outcome*. This is why a swapped call is not a compile error and the test still goes green or red correctly. The difference appears **only in the failure message**. When the values differ, JUnit produces text like: ``` org.opentest4j.AssertionFailedError: expected: <5> but was: <7> ``` It literally labels the first argument 'expected' and the second 'was' (actual). If you wrote `assertEquals(total, 5)` and `total` is 7, the message becomes 'expected: <7> but was: <5>' — claiming you expected 7 (your bug) and got 5 (your correct literal). That is backwards and will waste your debugging time. ## The same convention across the family Every comparing assertion in JUnit 5 uses **(expected, actual)**: `assertEquals`, `assertArrayEquals(expectedArray, actualArray)`, `assertIterableEquals(expectedList, actualList)`, and `assertSame(expectedRef, actualRef)`. Memorize one rule, apply it everywhere. ## How to stop making the mistake Because the compiler cannot enforce roles (both arguments are just `Object`), the common cure is a **fluent assertion library** such as **AssertJ**, where you write `assertThat(actual).isEqualTo(expected)`. Here the subject under test always comes first inside `assertThat(...)`, and the expected value goes inside `isEqualTo(...)`, so the roles are read in plain English and cannot be swapped silently.

  • If swapping arguments doesn't change pass/fail, why care at all?
    Because the diagnostic message labels the values 'expected' and 'actual'. A swap makes the message lie about which value was yours versus the code's, sending you debugging the wrong side and costing time on every failure.
  • How does AssertJ remove the ordering trap?
    Its fluent form assertThat(actual).isEqualTo(expected) puts the value under test inside assertThat() and the expectation inside isEqualTo(), so the roles read like English and can't be silently transposed.

saying these in an interview costs you the question

  • Claiming a swapped argument order makes the test pass when it should fail (it doesn't — only the message is wrong)
  • Saying assertEquals(actual, expected) is the JUnit convention
  • Thinking the compiler catches the swap

context