Advanced 30 min read

Enforce Validation Rules

By the end of this lesson, you'll be able to:

  • Validate that a loan amount and income are both positive
  • Validate that a credit score falls within a realistic range
  • Write tests confirming both valid and invalid input are handled correctly

Prerequisites: "Build the Calculation Engine"

Validating the inputs

public class LoanValidationException extends Exception {}

public class LoanValidationService {
    public void validate(Decimal requestedAmount, Decimal annualIncome, Decimal creditScore) {
        if (requestedAmount == null || requestedAmount <= 0) {
            throw new LoanValidationException('Requested amount must be positive.');
        }
        if (annualIncome == null || annualIncome <= 0) {
            throw new LoanValidationException('Annual income must be positive.');
        }
        if (creditScore == null || creditScore < 300 || creditScore > 850) {
            throw new LoanValidationException('Credit score must be between 300 and 850.');
        }
    }
}

Exactly Module 22's LibraryException and Module 23's InventoryException pattern, applied here — one dedicated exception type, and every validation rule from Lesson 1's design stated as a clear, individually-testable condition.

Testing the rejection paths

@isTest
private class LoanValidationServiceTest {
    @isTest
    static void negativeAmountThrows() {
        LoanValidationService validator = new LoanValidationService();
        try {
            validator.validate(-1000, 50000, 700);
            System.assert(false, 'Expected a LoanValidationException');
        } catch (LoanValidationException e) {
            System.assert(e.getMessage().contains('amount'));
        }
    }

    @isTest
    static void creditScoreAbove850Throws() {
        LoanValidationService validator = new LoanValidationService();
        try {
            validator.validate(10000, 50000, 900);
            System.assert(false, 'Expected a LoanValidationException');
        } catch (LoanValidationException e) {
            System.assert(e.getMessage().contains('Credit score'));
        }
    }
}

This is Module 31's "Testing Exceptions" lesson, applied to real project code the moment it's written — the try/System.assert(false)/catch pattern, one test method per invalid-input scenario.

Testing the acceptance path too

@isTest
static void validInputsDoNotThrow() {
    LoanValidationService validator = new LoanValidationService();
    validator.validate(10000, 50000, 700); // should complete without throwing
    System.assert(true); // reaching this line confirms no exception was thrown
}

Exactly Module 31's "confirm it does NOT throw" habit — a valid set of inputs deserves its own explicit test, not just an assumption that "the rejection tests passing" implies the acceptance path works too.

Exercise

Write a test confirming that a null annualIncome throws a LoanValidationException.

Show hint

Use the try/System.assert(false)/catch pattern.

APEX

Enforce Validation Rules Quiz

1. Why does this lesson test validInputsDoNotThrow as its own separate test?

Log in to submit the quiz and save your score.

My Notes

Log in to keep private notes on this lesson.

Questions about this lesson

No questions yet — be the first to ask.

Log in to ask a question about this lesson.

Summary

Before the approval decision itself, this lesson validates the raw inputs — and, following this module's pattern, tests both the rejection and acceptance paths immediately.