JUnit4 Assertions Explained
Unit tests exist to prove that a piece of code behaves the way we expect. Assertions turn those expectations into executable checks. In JUnit 4, the org.junit.Assert class provides static methods for this purpose. They compare expected values with actual outcomes and raise an AssertionError when a check fails.
The typical pattern is straightforward. You provide the expected value and the actual value, or you provide a boolean condition. If the condition is false, the test fails immediately. Most assertion methods also accept a String message, which is useful for adding context.
import static org.junit.Assert.*;
Comparing Values with assertEquals
The assertEquals method verifies equality. It supports primitives, objects, and collections through the equals method.
@Test
public void testAdd() {
Calculator calculator = new Calculator();
assertEquals(5, calculator.add(2, 3));
}
You can add a custom message:
assertEquals("The result is incorrect", 5, calculator.add(2, 3));
When comparing strings, prefer explicit overloads. This avoids ambiguity and misleading failures.
Checking Conditions and Nulls
assertTrue and assertFalse validate boolean logic.
assertNull and assertNotNull validate the absence or presence of a value.
@Test
public void testCondition() {
List<String> items = new ArrayList<>();
assertTrue("The list should be empty", items.isEmpty());
items.add("item");
assertFalse("The list should not be empty");
}
Identity vs Equality
assertSame checks reference identity with ==. assertEquals checks logical equality with equals. They are not interchangeable.
String first = new String("hello");
String second = new String("hello");
assertEquals(first, second); // passes
assertSame(first, second); // fails
Comparing Arrays
assertArrayEquals compares array size and elements.
@Test
public void testArray() {
int[] expected = {1, 2, 3};
int[] actual = sort(new int[]{3, 1, 2});
assertArrayEquals(expected, actual);
}
Using assertThat and Matchers
JUnit 4 includes Hamcrest through assertThat. The syntax is more readable and gives better failure messages.
import static org.hamcrest.CoreMatchers.*;
@Test
public void testHamcrest() {
int age = 20;
assertThat(age, is(20));
assertThat(age, greaterThan(18));
assertThat("Hello World", both(startsWith("Hello")).and(containsString("World")));
}
Common matchers include is, not, allOf, anyOf, hasItem, and hasSize.
Exception Assertions
JUnit 4 offers two main approaches.
Use @Test(expected = ...) for simple exception type checks.
@Test(expected = IllegalArgumentException.class)
public void testException() {
divide(10, 0);
}
For richer checks, use try, catch, and fail.
@Test
public void testExceptionDetail() {
try {
divide(10, 0);
fail("IllegalArgumentException should be thrown");
} catch (IllegalArgumentException e) {
assertEquals("The divisor cannot be zero", e.getMessage());
}
}
The fail Method
fail immediately marks a test as failed. It is helpful when code should not reach a certain point.
if (result != null) {
fail("The result should not exist");
}
Choosing the Right Assertion
Use assertEquals for value comparisons. Use assertSame for reference identity. Use assertThat for expressive domain checks. Use exception assertions to verify failures. Use fail to guard unreachable paths.
Choosing correctly prevents misleading tests and helps teams write clearer specifications.
Best Practices
- Focus one test on one behavior.
- Prefer
assertThatwhen using Hamcrest. - Add useful messages for complex assertions.
- Distinguish equality from identity.
- Assert concrete expected values.
Avoid weak checks like assertTrue(result != null) when content matters. Prefer assertEquals or assertThat.
Final Thoughts
JUnit 4 assertions are simple but powerful. They help turn vague failures into precise feedback. By combining built-in assertions, matchers, exception checks, and fail, teams can build stronger unit tests.