Skip to content
IRC-Coding IRC-Coding
Unit Tests Test Doubles AAA Arrange Act Assert Isolated Tests Fast Tests Meaningful Tests Maintainable Tests

Characteristics of Good Unit Tests

Good unit tests: isolated, fast, meaningful, maintainable & easy to run. With test doubles, AAA pattern & best practices.

S

schutzgeist

2 min read

Characteristics of Good Unit Tests

This article is a glossary entry on characteristics of good unit tests – including exam questions and tags.

In a Nutshell

Good unit tests are correct, isolated, fast, meaningful, maintainable, and easy to execute. They provide quick, reliable feedback and enable safe refactoring.

Compact Technical Description

1. Correct

Test verifies what it should verify – no false assumptions, no random results.

2. Isolated

No dependencies on external systems (DB, network, file system). Instead, use test doubles (stubs, mocks, fakes).

3. Fast

Execution in the millisecond range, so hundreds of tests can run in seconds (CI feedback).

4. Meaningful

Clear test names, understandable Arrange/Act/Assert structure, precise assertions with meaningful error messages.

5. Maintainable

No duplicated code (DRY), shared helper libraries, refactoring-safe.

6. Easy to Execute

One command starts all tests, no manual setup required, deterministic results.

Exam-Relevant Key Points

  • AAA (Arrange, Act, Assert) as structure
  • Test doubles: Stub (predefined responses) vs. Mock (verify expectations)
  • Naming: methodName_condition_expectedResult
  • Explicitly test edge cases and error scenarios
  • No “magic” numbers, use constants
  • Meaningful assertions (e.g., assertEquals(expected, actual, message))
  • Make tests independent (order doesn’t matter)
  • Deterministic (no randomness, no time dependencies)

Core Components

  1. Test structure (AAA)
  2. Test doubles (Stub, Mock, Fake, Spy)
  3. Naming conventions
  4. Assertions (clear error messages)
  5. Test data (Factories, Builder)
  6. Isolation (no external dependencies)
  7. Speed (ms range)
  8. Independence (order doesn’t matter)
  9. Determinism (no randomness/time)
  10. Maintainability (DRY, refactoring-safe)

Practical Example (Discount Calculation)

// Naming: calculateDiscount_newCustomer_standardItem_expectsZeroPercent
@Test
public void calculateDiscount_newCustomer_standardItem_expectsZeroPercent() {
    // Arrange
    Customer customer = new Customer(CustomerType.NEW);
    Item item = new Item(ItemType.STANDARD);
    DiscountService service = new DiscountService();

    // Act
    int discount = service.calculateDiscount(customer, item);

    // Assert
    assertEquals(0, discount, "New customer should receive no discount");
}

Advantages and Disadvantages

Advantages

  • Quick feedback (ms)
  • High fault localization
  • Safe refactoring
  • Low maintenance costs with good structure

Disadvantages

  • Initial effort for test doubles
  • Risk of over-engineering with too many helper libraries

Typical Exam Questions (with Short Answer)

  1. What does AAA mean? Arrange (prepare), Act (execute), Assert (verify).
  2. Difference between Stub and Mock? Stub provides fixed responses; Mock verifies that interactions occurred.
  3. Why is isolation important? Prevents external systems from slowing down tests or making them unreliable.
  4. What is the naming convention for good tests? methodName_condition_expectedResult.

Most Important Sources

  1. https://martinfowler.com/articles/practical-test-pyramid.html
  2. https://junit.org/junit5/docs/current/user-guide/
  3. https://testing.googleblog.com
Back to Blog
Share:

Related Posts