In the test pyramid, unit tests form the wide base: many, fast and cheap. They are what gives the team the courage to refactor without fear. But writing good unit tests is a skill — and it has pitfalls.
What a unit test is (and isn't)
A unit test verifies a unit of behavior in isolation, without touching the database, network or file system. If it needs a server up and running, it's probably an integration test in disguise.
The AAA pattern
A good test reads like a little story: Arrange, Act, Assert.
@Test
void deveAplicarDescontoParaClienteVip() {
// Arrange
Carrinho carrinho = new Carrinho(new Cliente(Tipo.VIP));
carrinho.adicionar(new Item("Livro", 100.0));
// Act
double total = carrinho.total();
// Assert
assertEquals(90.0, total); // 10% VIP discount
}
What makes a good test
- Fast: thousands of them run in seconds.
- Deterministic: same input, same result, always.
- Isolated: doesn't depend on execution order or on other tests.
- Focused: tests one behavior; the name describes the business rule.
What NOT to test
Don't test implementation details or trivial getters/setters. Test behavior, not internal structure — that way the test survives refactoring.
100% coverage doesn't mean quality. It means every line ran — not that every line is correct.
Conclusion
Unit tests are the highest-return investment in quality: instant feedback, living documentation of behavior and the confidence to evolve the code. Start with them before moving up the pyramid.