aer
Mock Managed Package Classes

Mock Managed Package Classes

Managed packages run inside their own namespaces, which means you cannot redeclare their classes inside your local project. aer package edit lets you override individual symbols in a .pkg file so your tests can replace network calls, logging, or other side effects with deterministic behavior. This walkthrough shows how to stub oslog.Log so tests can verify log payloads without depending on the real logger.

Sample service under test

Assume a service class writes audit events through the oslog package:

public with sharing class BillingService {
    public static void invoice(Id orderId) {
        oslog.Log.info('Invoicing order ' + orderId);
        // ... remainder of the implementation ...
    }
}

The test suite wants to assert which messages are emitted. Rather than hitting the actual logger, we will replace oslog.Log with a lightweight stub that captures calls in memory.

Inspect the package

List the symbols inside your oslog archive to confirm the class name and namespace:

aer package list packages/oslog.pkg --inner-classes

To review the Apex signature, show the specific class:

aer package show packages/oslog.pkg oslog.Log

The command prints the class definition—including constructors, methods, and modifiers—so you know what the stub must implement.

Override the class with a stub

Use aer package edit to extract the class into your editor. The changes you save are written back into the .pkg file and will apply the next time the package loads.

aer package edit packages/oslog.pkg oslog.Log

Replace the body with a test-friendly implementation that records messages instead of forwarding them:

// File: packages/oslog.pkg (edited via `aer package edit`)
public with sharing class Log {
    public class Entry {
        public String level;
        public String message;

        public Entry(String level, String message) {
            this.level = level;
            this.message = message;
        }
    }

    private static List<Entry> history = new List<Entry>();

    public static void info(String message) {
        history.add(new Entry('INFO', message));
    }

    public static void warn(String message) {
        history.add(new Entry('WARN', message));
    }

    public static void reset() {
        history.clear();
    }

    public static List<Entry> entries() {
        return history.deepClone(true);
    }
}

After saving, re-run aer package show to confirm the updated implementation is embedded in the package:

aer package show packages/oslog.pkg oslog.Log

aer prints the stubbed Apex code, verifying that the override is active.

Drive tests with the mock

Point aer test at the edited package. The service now talks to the stub during the entire watch/test loop.

aer test force-app/main/default \
  --package packages/oslog.pkg

In your test you can reset and inspect the captured log entries:

@IsTest
private class BillingServiceTest {
    @IsTest
    static void invoicesEmitLogEntry() {
        oslog.Log.reset();

        BillingService.invoice(Id.valueOf('001000000000001'));

        List<oslog.Log.Entry> entries = oslog.Log.entries();
        System.assertEquals(1, entries.size());
        System.assertEquals('INFO', entries[0].level);
        System.assertEquals('Invoicing order 001000000000001', entries[0].message);
    }
}

Because the stub lives inside the .pkg file, nothing leaks into production metadata, and you can tailor the override as your tests evolve. If you need to revert the edits, rerun aer package edit packages/oslog.pkg oslog.Log and restore the original contents, or regenerate the package from its source.

© 2012–2025 October Swimmer.