Project setup
Tests live in the same project as the code they check. Maven needs two things to run them: the JUnit library in the dependencies and the Surefire plugin, which finds test classes and runs them in the test phase. This lesson does not teach Maven itself — only the part you need for tests.
Creating the project
Any Maven project will do. A new one is created by the standard archetype:
mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.5 \
-DgroupId=com.example -DartifactId=blog -Dpackage=com.example.blog \
-DinteractiveMode=false
cd blogThe archetype adds JUnit 5.11 and the sample classes App and AppTest — delete both and replace pom.xml with the version below.
pom.xml
<!-- pom.xml -->
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>blog</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>25</maven.compiler.release>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>6.1.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.6.0</version>
</plugin>
</plugins>
</build>
</project>| Part | Why it is needed |
|---|---|
junit-bom | A BOM (bill of materials) fixes the versions of all JUnit modules in one place, so the dependencies below have no version |
junit-jupiter | The API for writing tests, parameterized tests and the engine that runs them |
scope test | The library is available only to tests and does not get into the finished program |
maven-surefire-plugin | Runs the tests; the version is pinned so the build does not depend on Maven defaults |
Where the code goes
blog/
├── pom.xml
└── src/
├── main/java/com/example/shop/PriceCalculator.java the code
└── test/java/com/example/shop/PriceCalculatorTest.java its testA test lives in src/test/java in the same package as the class it tests. That way it sees package-private members, and the structure of both folders matches.
The class under test
Create src/main/java/com/example/shop/PriceCalculator.java:
// src/main/java/com/example/shop/PriceCalculator.java
package com.example.shop;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class PriceCalculator {
public BigDecimal total(BigDecimal price, int quantity) {
if (quantity <= 0) {
throw new IllegalArgumentException("Quantity must be positive: " + quantity);
}
return price.multiply(BigDecimal.valueOf(quantity))
.setScale(2, RoundingMode.HALF_UP);
}
public BigDecimal applyDiscount(BigDecimal amount, int percent) {
if (percent < 0 || percent > 100) {
throw new IllegalArgumentException("Discount must be between 0 and 100: " + percent);
}
BigDecimal factor = BigDecimal.valueOf(100 - percent).movePointLeft(2);
return amount.multiply(factor).setScale(2, RoundingMode.HALF_UP);
}
}total() multiplies the price by the quantity, applyDiscount() takes a percentage off. Both round to cents. Run mvn test — Maven downloads JUnit and reports BUILD SUCCESS, there are no tests yet.
Common mistake
If you put a test into src/main/java, the project stops compiling: JUnit is available only to code in src/test/java because of scope test.
[ERROR] /.../src/main/java/com/example/shop/WrongPlaceTest.java:[3,29] package org.junit.jupiter.api does not existMove the test class to src/test/java, keeping the package.