ScreenshotNeo

BlogHow-to

How to Write and Run Test Cases in Java

Write a JUnit Jupiter test, configure Maven or Gradle to discover it, and run it from the command line. Includes runnable examples and fixes for common failures.

By the ScreenshotNeo team4 October 202610 min read

To write and run a test case in Java, create a test method annotated with JUnit Jupiter’s @Test, use assertions to check the expected behavior, add JUnit to the project’s test dependencies, and run the test task for the build tool your project already uses. Maven projects commonly keep tests in src/test/java and run them with mvn test; Gradle projects use the Java plugin’s test source set and commonly run ./gradlew test.

1. Write a JUnit Jupiter test

Here is a complete, small test class. It checks an expected result against the actual expression:

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

class CalculatorTest {
    @Test
    void addsTwoNumbers() {
        assertEquals(4, 2 + 2);
    }
}

@Test marks the method as a test. The assertion fails the test if the expected value (4) differs from the actual value (2 + 2). In a real project, exercise behavior provided by your code rather than a constant arithmetic expression:

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

class PriceCalculatorTest {
    @Test
    void appliesTenPercentDiscount() {
        PriceCalculator calculator = new PriceCalculator();

        int totalInCents = calculator.afterDiscount(1_000, 10);

        assertEquals(900, totalInCents);
    }
}

This second example assumes your application has a PriceCalculator class with an afterDiscount(int, int) method. Replace the class, call, and expected value with behavior in your project. A useful test name says what behavior is being checked. Keep a test understandable and, where practical, independent of other tests.

2. Add and run tests with Maven

Use the Maven configuration already in the repository. The example below uses JUnit Jupiter and Maven Surefire to run tests on the JUnit Platform. Keep dependency and plugin versions aligned with the project’s supported Java and Maven setup; do not copy version numbers from old JUnit examples without checking current project requirements.

Configure pom.xml

<dependencies>
  <dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>YOUR_JUNIT_VERSION</version>
    <scope>test</scope>
  </dependency>
</dependencies>

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-surefire-plugin</artifactId>
      <version>YOUR_SUREFIRE_VERSION</version>
    </plugin>
  </plugins>
</build>

Replace the placeholders with versions selected for your project. Surefire needs a JUnit Platform TestEngine at test runtime; the Jupiter dependency supplies the Jupiter API and engine for the usual setup. If the project manages plugin or dependency versions in a parent POM or version catalog, follow that convention instead of adding a conflicting version here.

Place and run the test

  1. Save the test as src/test/java/CalculatorTest.java, or in the test source directory configured by the project. The conventional Maven test source directory is src/test/java.
  2. From the directory containing pom.xml, run mvn test. If the repository includes a Maven wrapper, use ./mvnw test to use its configured Maven version.
  3. Read the test summary and reports. A successful compile alone does not establish that tests were discovered and executed.

To select a test class with Surefire, a common form is mvn -Dtest=CalculatorTest test. Selection and discovery can depend on the Surefire version and project configuration, so check the actual plugin setup if the filter matches nothing.

Legacy JUnit 4 tests

For a project migrating to JUnit Platform while retaining JUnit 4 tests, Surefire documents running JUnit 4 through the Vintage engine. Its current JUnit Platform documentation identifies JUnit 4.12 as the minimum supported version in that setup. Confirm the Surefire version and the project’s actual dependencies before adding Vintage; a Jupiter-only project does not need it.

3. Add and run tests with Gradle

For a Gradle Java project, add Jupiter to the test dependencies and configure the test task to use the JUnit Platform. The Java plugin provides a test source set and wires it to the test task.

Configure build.gradle (Groovy DSL)

plugins {
    id 'java'
}

repositories {
    mavenCentral()
}

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter:YOUR_JUNIT_VERSION'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

test {
    useJUnitPlatform()
}

Replace YOUR_JUNIT_VERSION with a version selected for the project. If you use the Kotlin DSL, the equivalent dependency and task configuration looks like this:

plugins {
    java
}

repositories {
    mavenCentral()
}

dependencies {
    testImplementation("org.junit.jupiter:junit-jupiter:YOUR_JUNIT_VERSION")
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

tasks.test {
    useJUnitPlatform()
}

Use the project’s existing repository and dependency management conventions if they differ from these standalone examples.

Place and run the test

  1. Save the class under src/test/java for a standard Java source layout, or in the configured test source set.
  2. Run ./gradlew test from the project root when the Gradle wrapper is present. Otherwise use the project’s installed Gradle command, commonly gradle test.
  3. Review the task result and test report to confirm the test ran and passed.

To run a single test class, Gradle supports test filtering, for example:

./gradlew test --tests CalculatorTest

For a method-level filter, use the fully qualified class and method pattern supported by the project’s Gradle version, such as --tests 'com.example.CalculatorTest.addsTwoNumbers'. If no tests match, inspect the task output and filter spelling.

4. Maven or Gradle: use the project’s build

Question Maven Gradle
Typical test location src/test/java Java plugin test source set, commonly src/test/java
JUnit dependency Test-scoped dependency in pom.xml testImplementation, with runtime launcher as configured
JUnit Platform configuration Surefire plus a runtime test engine useJUnitPlatform() on the test task
Typical command mvn test or ./mvnw test ./gradlew test
Targeted run Surefire selection such as -Dtest=CalculatorTest Filter such as --tests CalculatorTest

When both are plausible for a new project, choose based on repository conventions, dependency configuration, filtering and reports, CI integration, and team familiarity. The cited documentation does not establish a universal performance or quality winner. For an existing project, use its build tool and wrapper so local and CI runs follow the same configuration.

5. How test discovery and reports work

A test must be compiled from the configured test source set, and the build must have a runner that can discover its framework. With JUnit Jupiter, that means the Jupiter API is available to compile the test and a compatible JUnit Platform engine and build-tool integration are available at runtime. Maven Surefire and Gradle’s test task each apply discovery and filtering rules; custom includes, excludes, naming patterns, or filters can prevent an otherwise valid test from running.

Use the build output and generated reports to distinguish among compilation errors, test failures, errors during execution, skipped tests, and zero tests discovered. For Maven, inspect the test summary and Surefire reports under target/surefire-reports. For Gradle, inspect the test task output and the HTML report under build/reports/tests/test when generated by the project configuration.

6. Troubleshooting

Symptom Likely cause What to check or fix
@Test or assertion import does not compile The JUnit API is missing from the test compile classpath, or the import is for a different JUnit version. Check the Maven test-scoped dependency or Gradle testImplementation, then confirm the import is org.junit.jupiter.api.Test for Jupiter.
Tests compile, but zero tests run Wrong source directory, class naming or discovery rules, active filter, or missing platform engine. Confirm the test source set, class and method names, include/exclude settings, filters, and runtime engine. Inspect the build summary rather than relying on compilation.
Maven reports no tests Surefire is not selecting the class, or plugin configuration overrides defaults. Check the Surefire version, configured includes/excludes, class naming, and -Dtest value. Inspect Surefire reports.
Gradle ignores Jupiter tests The test task may not use the JUnit Platform, or runtime dependencies may be incomplete. Verify useJUnitPlatform(), Jupiter test dependencies, and the launcher configuration against the project’s Gradle version.
JUnit 4 tests stop running after migration The selected Platform setup may not include Vintage, or the JUnit 4 version may be unsupported by that setup. Check the actual Surefire configuration and Vintage engine requirement. Surefire’s documented setup identifies JUnit 4.12 as the minimum in this configuration.
IDE run differs from command line The IDE and build may use different JDKs, project settings, filters, or dependency resolution. Run the wrapper command from the repository root, compare the IDE’s selected JDK and project import, and inspect the same build configuration and reports.
Test fails only when run with other tests It may depend on shared mutable state, execution order, or external resources. Run it alone and with the full suite, then inspect setup and cleanup, shared state, and resource use. Avoid relying on unspecified execution order.

7. Performance, reliability, and cost

For a test suite that is slow or inconsistent, first identify whether time is spent compiling, starting the test runtime, executing test code, or waiting on external resources. The cited build-tool documentation describes task execution, filtering, reports, and troubleshooting, but does not support a general claim that Maven or Gradle is faster. Compare runs using the same code, JDK, dependencies, machine, and task scope before drawing a project-specific conclusion.

Keep routine tests deterministic where practical: control inputs and external dependencies, clean up resources, and avoid depending on test ordering. A targeted filter is useful while debugging one case; run the project’s normal test task before relying on a change so the broader suite is included. No coverage target or productivity statistic is implied by this guide.

JUnit Jupiter is an open-source test framework; this workflow does not require a paid screenshot or testing service. Build time and CI cost depend on the project’s configuration and execution environment. For unrelated website capture work, ScreenshotNeo’s pricing is described separately below.

8. Capture website screenshots in Java workflows

Java unit tests often verify application behavior without a browser. If a separate task in your workflow needs a website screenshot, you can call a screenshot API from Java using the standard HTTP client. This is a runnable Java 11+ example that writes the returned image bytes to a file. Replace the key and target URL; add URL encoding for arbitrary URL characters when constructing query parameters in production.

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;

public class CaptureScreenshot {
    public static void main(String[] args) throws Exception {
        String accessKey = System.getenv("SCREENSHOTNEO_API_KEY");
        if (accessKey == null || accessKey.isBlank()) {
            throw new IllegalStateException("Set SCREENSHOTNEO_API_KEY first");
        }

        String url = "https://stripe.com";
        String requestUrl = "https://api.screenshotneo.com/v1/shot"
                + "?access_key=" + accessKey
                + "&url=" + java.net.URLEncoder.encode(
                        url, java.nio.charset.StandardCharsets.UTF_8);

        HttpRequest request = HttpRequest.newBuilder(URI.create(requestUrl))
                .timeout(Duration.ofSeconds(90))
                .GET()
                .build();
        HttpResponse<byte[]> response = HttpClient.newHttpClient().send(
                request, HttpResponse.BodyHandlers.ofByteArray());
        if (response.statusCode() < 200 || response.statusCode() >= 300) {
            throw new IllegalStateException("Screenshot request failed: HTTP "
                    + response.statusCode() + " "
                    + new String(response.body(), java.nio.charset.StandardCharsets.UTF_8));
        }
        Files.write(Path.of("shot.webp"), response.body());
    }
}

Compile and run with a Java 11 or newer JDK, supplying the key in the environment:

export SCREENSHOTNEO_API_KEY=YOUR_API_KEY
javac CaptureScreenshot.java
java CaptureScreenshot

See the ScreenshotNeo API documentation for request options and response details. A screenshot response can include verdict and billing headers; do not treat every returned response as a billable clean capture.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server for developers. One GET request can return a PNG, JPEG, WebP, or PDF. For example, use cURL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo accepts cookie and consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing. Its MCP server offers take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Every feature is on every plan. See the API docs and sign up free for 1,000 screenshots a month, no card required.

FAQ

Can I use JUnit without Maven or Gradle?

Yes, but the project still needs the JUnit API and an engine on the classpath plus a way to launch the tests. For a project, its existing build tool usually gives the clearest repeatable command for local and CI runs.

Does mvn package run tests?

Maven lifecycle phases typically include earlier phases such as test, but confirm that the project has not customized or skipped test execution. Use mvn test when you specifically want the test phase.

Should I put unit tests in src/main/java?

No. Keep test code in the configured test source set, conventionally src/test/java, so the build compiles and runs it as tests.

Do I need both JUnit 4 and JUnit Jupiter?

No. Use the framework already supported by the project. Add Vintage only when the configured JUnit Platform runner needs to execute legacy JUnit 4 tests.