DML Mocking Patterns

Overview

DML mocking patterns make service logic testable without relying on heavy real-database setup in every test.

Use this approach when business logic complexity is high and test speed/stability matter.

Consensus Best Practices

Pattern 1: Repository Boundary

public interface IContactRepository {
    void insertContacts(List<Contact> contacts);
    void updateContacts(List<Contact> contacts);
}

public with sharing class ContactRepository implements IContactRepository {
    public void insertContacts(List<Contact> contacts) { insert contacts; }
    public void updateContacts(List<Contact> contacts) { update contacts; }
}

Pattern 2: Service with Injected Dependency

public with sharing class ContactService {
    private IContactRepository repo;

    public ContactService(IContactRepository repo) {
        this.repo = repo;
    }

    public void processContacts(List<Contact> contacts) {
        // validate + enrich
        repo.insertContacts(contacts);
    }
}

Pattern 3: In-Memory Test Double

@IsTest
private class InMemoryContactRepository implements IContactRepository {
    public List<Contact> inserted = new List<Contact>();
    public List<Contact> updated = new List<Contact>();

    public void insertContacts(List<Contact> contacts) { inserted.addAll(contacts); }
    public void updateContacts(List<Contact> contacts) { updated.addAll(contacts); }
}

Pattern 4: Interaction Assertions

@IsTest
private class ContactServiceTests {
    @IsTest
    static void processContacts_callsRepository() {
        InMemoryContactRepository mockRepo = new InMemoryContactRepository();
        ContactService service = new ContactService(mockRepo);

        service.processContacts(new List<Contact>{ new Contact(LastName = 'Test') });
        System.assertEquals(1, mockRepo.inserted.size());
    }
}

Tradeoffs