jUnit
AssertContains
testing
Java
unit testing

AssertContains on strings in jUnit

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

JUnit does not ship a built-in assertContains method for strings. The normal pattern is to assert that actual.contains(expected) is true, or to use a richer assertion library such as AssertJ or Hamcrest if you want more expressive failure messages. The important part is choosing an assertion style that keeps test failures readable.

Use assertTrue with String.contains

The simplest JUnit-only version is:

java
1import static org.junit.jupiter.api.Assertions.assertTrue;
2
3import org.junit.jupiter.api.Test;
4
5class MessageTest {
6    @Test
7    void responseContainsId() {
8        String response = "Created order with id=42";
9
10        assertTrue(response.contains("id=42"));
11    }
12}

This is perfectly valid. It keeps the dependency list small and works well for many tests.

The weakness is not correctness. The weakness is failure output. If the assertion fails, the message may be less descriptive than a purpose-built string assertion.

Add a Helpful Failure Message

When substring checks are central to the test, include a message that shows what was expected.

java
1import static org.junit.jupiter.api.Assertions.assertTrue;
2
3import org.junit.jupiter.api.Test;
4
5class MessageTest {
6    @Test
7    void responseContainsId() {
8        String response = "Created order with id=42";
9
10        assertTrue(
11            response.contains("id=42"),
12            () -> "Expected substring id=42 in response: " + response
13        );
14    }
15}

The supplier form keeps the message lazy and makes failures much easier to diagnose.

Guard Against Null Explicitly

If the source string could be null, do not hide that inside a boolean expression. Assert the null expectation first so the failure tells you what actually went wrong.

java
1import static org.junit.jupiter.api.Assertions.assertNotNull;
2import static org.junit.jupiter.api.Assertions.assertTrue;
3
4import org.junit.jupiter.api.Test;
5
6class MessageTest {
7    @Test
8    void responseContainsToken() {
9        String response = getResponse();
10
11        assertNotNull(response, "response should not be null");
12        assertTrue(response.contains("token"));
13    }
14
15    private String getResponse() {
16        return "token=abc123";
17    }
18}

This is clearer than writing response != null && response.contains("token") inside one assertion.

Prefer Richer Assertion Libraries When Readability Matters

If your project already uses AssertJ or Hamcrest, string containment becomes more readable.

With AssertJ:

java
1import static org.assertj.core.api.Assertions.assertThat;
2
3import org.junit.jupiter.api.Test;
4
5class MessageTest {
6    @Test
7    void responseContainsId() {
8        String response = "Created order with id=42";
9
10        assertThat(response).contains("id=42");
11    }
12}

This reads closer to English and usually produces better failure messages. JUnit is still the test runner here; AssertJ is just providing richer assertions.

Handle Case Sensitivity Deliberately

A raw contains check is case-sensitive. If that is not what you want, normalize both sides or use an assertion library feature that says so explicitly.

java
1import static org.junit.jupiter.api.Assertions.assertTrue;
2
3import java.util.Locale;
4import org.junit.jupiter.api.Test;
5
6class MessageTest {
7    @Test
8    void responseContainsSubstringIgnoringCase() {
9        String response = "Order Status: Completed";
10        String expected = "status: completed";
11
12        assertTrue(
13            response.toLowerCase(Locale.ROOT).contains(expected.toLowerCase(Locale.ROOT))
14        );
15    }
16}

Using Locale.ROOT avoids locale-dependent casing surprises.

Consider Whether Containment Is the Right Check

Sometimes people reach for a substring assertion when they really want:

  • equality
  • a prefix or suffix check
  • a regex or pattern match
  • structured data validation such as JSON parsing

For example, if the response is JSON, checking contains("\"status\":\"ok\"") is usually weaker than parsing the JSON and asserting the actual field value.

So use containment when the test intent is genuinely about substring presence, not because it is the fastest thing to type.

Common Pitfalls

  • Assuming JUnit has a built-in assertContains for strings.
  • Hiding null checks inside one large boolean expression.
  • Writing containment assertions for structured payloads that should be parsed instead.
  • Forgetting that String.contains is case-sensitive.
  • Choosing a weak failure message that makes debugging harder than necessary.

Summary

  • JUnit itself does not provide a dedicated string assertContains.
  • The standard JUnit approach is assertTrue(actual.contains(expected)).
  • Add clear failure messages and separate null assertions when needed.
  • AssertJ or Hamcrest can make containment tests more expressive.
  • Use substring assertions only when substring presence is truly the behavior you want to test.

Course illustration
Course illustration

All Rights Reserved.