Glossary · Testing fundamentals
Unit test
Also called: unit tests, unit testing
Definition
An automated test that checks a small piece of code, such as a function or class, in isolation from databases, networks and other services.
A unit test exercises one small unit of code, typically a function, method or class, and checks its output or behavior for given inputs. It runs in memory, without real databases, HTTP calls or file systems, so it takes milliseconds and fails for exactly one reason. Unit tests form the base of the test pyramid and are usually written by developers alongside the code.
Example (JUnit 5, Java 21)
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
class DiscountCalculatorTest {
private final DiscountCalculator calculator = new DiscountCalculator();
@ParameterizedTest
@CsvSource({ "99.99, 0.00", "100.00, 10.00", "250.00, 25.00" })
void appliesTenPercentFromOneHundred(double total, double expected) {
assertEquals(expected, calculator.discountFor(total), 0.001);
}
@Test
void rejectsNegativeTotals() {
assertThrows(IllegalArgumentException.class, () -> calculator.discountFor(-1));
}
}
Parameterized tests need the junit-jupiter-params artifact, which is included in the junit-jupiter aggregate dependency. (Real money code should use BigDecimal rather than double; it is kept simple here.)
What makes a good unit test
- Fast and deterministic. No sleeps, clocks, randomness or network. Inject a fixed
Clockinstead of callingLocalDate.now(). - Isolated. Dependencies are replaced with test doubles where they would make the test slow or unpredictable.
- One behavior per test, with a name that states it, so a failure explains itself.
- Tests behavior, not implementation. Assert on outputs and observable effects, not on private methods, so refactoring does not break tests.
Unit vs integration test
A unit test checks your logic with everything else replaced. An integration test checks that real components work together: your repository against a real database, your client against a real (or containerized) service. Unit tests catch logic errors cheaply; integration tests catch wiring, configuration, serialization and query mistakes that unit tests mock away. A suite of only unit tests can be fully green while the application fails to start.
How “unit” is defined
There is no universal answer. Some teams treat a single class as the unit and mock all collaborators. Others treat a small cluster of classes that implement one behavior as the unit and only replace things that cross a process boundary. The second style tends to produce tests that are less brittle under refactoring.