Mock the Base Apex Class in Tests

When writing unit tests for an extension provider class, sometimes we want to mock the super() method in the extension provider class. However, the Apex test framework does not support mocking objects or methods in a namespace that is different from where test classes are defined. This tutorial provides a workaround to allow us to mock super() in the extension provider class. To learn more about Apex’s namespace, refer to Default Namespaces in Apex on the Salesforce Developers blog.

The idea is to separate the logic for calling the super() default logic so that it can be mocked in the test.

Let’s walk through an example for testing the extension provider class.

Assume we have an extension provider class called Custom_Inventory that extends a Base Apex class CommerceDxSampleapp.CommerceDx_Inventory.

note: The Base Apex Class has its own namespace and is different from the org of the extension provider class.

Base Apex Class

The base Apex class looks like this:

global virtual class CommerceDxSampleapp.CommerceDx_Inventory {
    global virtual Integer calculateInventoryLevel (String webstoreId, String eventId){
        // Default Logic
        return 0;
    }
}

Extension Provider Class

note: The Custom_Inventory class belongs to current org's namespace._

To create an extension provider, add a class that extends the base Apex class:

public class Custom_Inventory extends CommerceDxSampleapp.CommerceDx_Inventory {
    public override Integer calculateInventoryLevel(String webstoreId, String eventId){
       // Invoke Base Class's default logic
       super.calculateInventoryLevel(webstoreId, eventId);
    }
}

1. Add "Virtual" to Extension Provider Classes

To make sure that we can mock the default logic, add a method that only calls super() and make it overridable by marking it as virtual. We also need to mark the class as virtual.

public virtual class Custom_Inventory extends CommerceDxSampleapp.CommerceDx_Inventory {
    public override Integer calculateInventoryLevel(String webstoreId, String eventId){
        return callDefault(webstoreId, eventId);
    }

    @TestVisible
    private virtual Integer callDefault(String webstoreId, String eventId){
        // Invoke Base Class's default logic
        return super.calculateInventoryLevel(webstoreId, eventId);
    }
}

2. Define the Test Class

Next, define the test class. (See Salesforce Developers to learn how to write an Apex test.)

MyTestClass

@isTest
public class MyTestClass {
    @isTest
    public static void testCalculateInventory(){

    }
}

3. Define the Inner Mock Class

Finally, define an inner mock class called Fake_Custom_Inventory to override the logic for the super() method that belongs to the base Apex class. Then the test method can use the mock class to return the expected result for the super() logic.

@isTest
public class MyTestClass {
    @isTest
    public static void testCalculateInventory(){
        Fake_Custom_Inventory fake_Custom_Inventory = new Fake_Custom_Inventory();
        // Assert the result is the same as mocked result defined below
        String webstoreId = 'fakeWebstoreId';
        String eventId = 'fakeEventId';
        System.assertEquals(-1, fake_Custom_Inventory.calculateInventoryLevel(webstoreId, eventId));
    }

    // Create a mock private class in the test class
    private class Fake_Custom_Inventory extends Custom_Inventory{
        public override Integer callDefault(String webstoreId, String eventId) {
            // Return a mocked result for testing
            return -1;
        }
    }
}