How do I decide what should and should not be unit tested?

Short answer

Unit test behavior that you own and that can break, especially logic with branches, rules, edge cases, and important failure paths.

Do not unit test code that merely repeats the framework, language, or library behavior unless you add meaningful logic around it.


Good candidates for unit tests

1. Business rules

If the code encodes a rule, test it.

Examples:

boolean isEligibleForDiscount(Customer customer) {
    return customer.isActive()
            && customer.getOrdersCount() >= 5
            && !customer.isBlacklisted();
}

This should be unit tested because it represents application-specific behavior.


2. Conditional logic and branching

Test code with if, switch, polymorphic behavior, strategy selection, validation paths, etc.

if (paymentAmount.compareTo(balance) > 0) {
    throw new InsufficientFundsException();
}

You should test:

  • amount less than balance
  • amount equal to balance
  • amount greater than balance
  • invalid amount if applicable

3. Edge cases

Unit tests are especially valuable around boundaries.

Examples:

  • zero
  • negative numbers
  • empty collections
  • null, if allowed
  • maximum/minimum values
  • duplicate values
  • time zone/date boundary cases
  • rounding and precision cases
  • permission boundaries

4. Error handling

If your code is supposed to throw, recover, retry, fallback, or translate errors, test that.

try {
    gateway.charge(request);
} catch (GatewayTimeoutException ex) {
    throw new PaymentUnavailableException("Payment provider is unavailable", ex);
}

This is worth testing because your application behavior depends on it.


5. Transformations and calculations

Any code that maps, calculates, normalizes, sorts, filters, or aggregates data is usually worth testing.

InvoiceSummary summary = invoiceCalculator.calculate(invoice);

Especially test:

  • rounding
  • currency precision
  • missing values
  • multiple item combinations
  • tax/discount rules

6. Public behavior of a class/module

Prefer testing the public API of a unit rather than every private method.

Instead of asking:

Should I test this private method?

Ask:

Is the behavior produced by this private method observable through the public method?

If yes, test through the public method.


7. Bugs that have occurred before

When you fix a bug, add a test that fails before the fix and passes after it.

This prevents regressions and documents the expected behavior.


Usually not worth unit testing

1. Simple getters and setters

Do not usually test this:

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

Especially with Lombok-generated accessors.


2. Framework wiring

Avoid unit testing things like:

@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;
}

You usually do not need a unit test just to verify that Spring injects dependencies. That belongs to integration tests if needed.


3. Repository methods provided by Spring Data JPA

This usually does not need a unit test:

Optional<User> findByEmail(String email);

Spring Data already tests its method parsing behavior. If the query is custom or complex, use a repository/integration test instead.


4. Trivial delegation

This is often not valuable:

public UserDto getUser(Long id) {
    return userClient.fetchUser(id);
}

Unless there is meaningful behavior such as validation, fallback, authorization, mapping, caching, or error translation.


5. Third-party library behavior

Do not unit test that Jackson serializes JSON, that BigDecimal adds numbers correctly, or that Spring MVC maps annotations correctly.

Test your configuration or behavior if you customized it.


6. Private implementation details

Avoid tests that know too much about internals.

Bad test focus:

Method calculateStepTwo() was called exactly once.

Better test focus:

Given these inputs, the invoice total is correct.


A practical decision checklist

Ask these questions:

  1. Does this code contain business logic?
    If yes, test it.

  2. Could this break in a way users or other systems would notice?
    If yes, test it.

  3. Does it have branches, edge cases, calculations, or state changes?
    If yes, test it.

  4. Would a test give me confidence to refactor it?
    If yes, test it.

  5. Am I only testing a framework, library, getter, setter, or annotation?
    If yes, probably do not unit test it.

  6. Would the test be more complex than the code being tested?
    If yes, reconsider. Maybe test at a higher level.

  7. Is this behavior better verified with an integration or end-to-end test?
    If yes, use that instead.


Rule of thumb

Use this rough guide:

Code type Unit test?
Business rules Yes
Calculations Yes
Validation logic Yes
Mapping with logic Yes
Error handling Yes
Edge cases Yes
Bug fixes Yes
Simple getters/setters Usually no
Lombok-generated methods Usually no
Spring dependency injection Usually no
Basic repository method names Usually no
Framework annotations Usually no
Third-party library behavior No

Example from a typical Spring/Jakarta application

Probably not worth unit testing:

@Getter
@Setter
@Entity
public class User {
    @Id
    private Long id;

    private String email;
}

Worth testing:

public class UserRegistrationService {

    public User register(String email, String password) {
        if (!emailValidator.isValid(email)) {
            throw new InvalidEmailException(email);
        }

        if (password.length() < 12) {
            throw new WeakPasswordException();
        }

        return userRepository.save(new User(email, passwordEncoder.encode(password)));
    }
}

Tests should cover:

  • valid registration
  • invalid email
  • weak password
  • password is encoded
  • duplicate email, if handled
  • repository failure, if translated or recovered from

Final guideline

Aim for tests that are:

  • behavior-focused
  • fast
  • clear
  • stable
  • useful during refactoring

Do not chase 100% coverage blindly. High coverage is nice, but meaningful coverage matters more.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.