Engineering

Adopting Salesforce ApexMocks Framework

October 23, 2020

October 23, 2020 by Jesus Gonzalez

When it comes to building a robust test suite for an enterprise application, the mocking technique is a must have in our developer tool-belt. It is a big enabler for crafting well architected applications and it is a well known standard in the industry for most of the advanced programming languages. However it is not that widely used in the Salesforce community. 

The thing is that the platform as such was not facilitating the task until the more-or-less recent delivery of the Stub API. Thus, the Salesforce developers were generally doing integration testing instead of true unit testing which is quite problematic, especially in the medium-long term and bigger applications. Integration tests are necessary, but its presence should be much lower.

Fortunately, a mocking framework based on Mockito, ApexMocks, came to the rescue back in 2014. Like Mockito, it is extremely useful and full of features. It is popular in the enterprise world, but surprisingly not that much adopted as one would expect. The truth is that the Salesforce engineering experience and history is very wide and different. But hopefully if you are reading this is because you are looking to know how to adopt ApexMocks into your project (and spread the word). So, let’s dive in! 

Steps to make your app ready for mocks

We could condense the transition to using ApexMock in three basic steps:

  1. Prepare your existing code.
  2. Import ApexMocks library.
  3. Learn the framework basics and start writing real unit tests.

Preparing your classes

You’ll have to be somehow versed in at least one particular programming concept to be ready to do mocks. But trust me, it is not hard at all and perhaps you already master it, and if you do feel free to jump to the next section. I’m talking about dependency injection. I explain the concept agnostic to any framework in my personal blog here. Although the theory there as a unit doesn’t reveal all the potential a specific tool can provide, I encourage you to read it as a starting point. Nevertheless, let me make kind of a dependency injection 101 here for you to get prepared for the next steps.

In plain English, dependency injection is a mechanism to delegate the instantiation of the classes you depend on to some other class. Said differently, instead of constructing classes, you receive the instances ready to use. So your dependencies are injected instead of built by the current class.

Perhaps the most popular dependency injection mechanism is the “instance as a param” in the constructor. E.g.:

public with sharing class MyDependentClass {

    private IMyInjectionInterface injectedInstance;

    public MyDependentClass(IMyInjectionInterface injectedInstance) {
        IMyInjectionInterface this.injectedInstance = injectedInstance;
    }

    public void delegateAction() {
        this.injectedInstance.performAction();
    }
}

This is a way to do inversion of control . Alternatively to the above you could make the injectedInstance to be a public apex property so that it can be replaced or similarly create a public setter method. All of them and any other you can think of are very valid mechanisms for our goal. 

Anyhow, that’s all the preparation work you need to do in your classes to be ready to start creating mock objects. Now, I encourage you to look for some classes you’d like to mock out and start doing these tweaks and amendments unless you are already following this design pattern. 

To make a project to grow in a sustainable manner, proper separation of concerns must be followed. But that’s a topic that requires its own series of blog posts. So, let’s move on.

Importing ApexMocks library

This is for sure the easiest step. Just visit the ApexMocks repository, clone it and import all the content into your version control system. Actually, you might have your own preferences when it comes to importing external tools into your main source, so the process is really up to you. All the ApexMocks classes are prefixed by “fflib_” so you’ll recognize them quite easily. Finally, in the ApexMocks repository, you’ll find a “deploy link” there to get it straight away in an org of yours if you want to play around before even importing it. It can’t be easier. 

Learning the basics and writing the first tests

Finally! We got into the point we were looking for when we initiated together the journey through this post. We’ll see first how a unit test with mocks looks like, and then what are your essential tools.

Anatomy of a unit test

I’m a big fan of the “given, when, thenBDD inspired unit tests. I don’t want to oversimplify the BDD concept, but for now we can say it is to structure your test in the form:

// Given
[prepare any data and/or the scenario]

// When
Test.startTest();
MyTargetClass.MyTargetMethod();
Test.stopTest();

// Then
System.assert[Equals]([my expected behavior/result against the real one]);

This will sound familiar to you. In the first block, you usually make your DMLs, some SOQLs, load specific users, etc (some of this might live in one or more @TestSetup annotated methods though). Then, you just invoke the class intended to be tested using one or more of the data you’ve just created to finally check the results or catch the errors. As you know, frequently this becomes problematic in Apex, especially with complex and heavily demanding processes making us apply not very orthodox approaches to workaround the problem. 

Regular unit test VS ApexMocks based unit test

Actually, the difference between regular unit tests and the ApexMocks based ones is somehow subtle. You’ll follow the same steps, but the tested method will receive a Stub instead of a regular instance that you use later to check the results.

 

Regular Unit Test ApexMocks-ish Unit Test
Given Create real data to set up the test scenario. Create mock objects and stubs.
When Invoke the unit-tested method. Invoke the unit-tested method.
Then Check the returned data or the exception for error cases. Check the returned data or the exception for error cases. Also check that the dependencies were invoked as expected.

 

Let me take a practical example from the aforementioned blog post to illustrate the difference and elaborate it further. Let’s say we have a House class which access is controlled by the SecurityService class. It already implements Dependency Injection and looks like follows.

public with sharing class House {
    @TestVisible
    private Boolean isDoorOpen = false;
    private ISecurityService security;

    public House(ISecurityService security) {
        this.security = security;
    }

    public void openDoor() {
        Boolean userHasAccess = this.security.isCurrentUserAllowedToEnter();
        if (!userHasAccess) {
            throw new SecurityException('You do not have access to this house.');
        }

        isDoorOpen = true;
    }
}

A valid classical unit test would look like follows:

@isTest
private class HouseTests {
    @isTest
    private static void openDoor_userHasAccess_doorOpen() {
        // Given
        User userWithAccess = new User(
            FirstName = 'Gregory,
            LastName = 'House',
            //...rest of params
        );
        insert userWithAccess;

        PermissionSet houseManagementPS =
            [SELECT Id FROM PermissionSet WHERE Name = 'HouseManagement'];

        insert new PermissionSetAssignment(
            AssigneeId = userWithAccess.id,
            PermissionSetId = houseManagementPS.Id);

        SecurityService securityHandler = new SecurityService();

        // When
        System.runAs(userWithAccess) {
            House standardHouse = new House(securityHandler);
            standardHouse.openDoor();
        }

        // Then
        System.assert(standardHouse.isDoorOpen, 'The door should be open.');
    }
}

We won’t discuss how complex it can become as the SecurityService grows. It is also patent that the test is tightly dependent on the SecurityService internals. Let’s see it with ApexMocks. Don’t get scared, I’ll explain each bit later on. 

@isTest
private class HouseTests {

    @isTest
    private static void openDoor_userHasAccess_doorOpen() {
        // Given
        fflib_ApexMocks mocks = new fflib_ApexMocks();
        SecurityService securityHandlerMock = 
            (SecurityService)mocks.mock(SecurityService.class);

        mocks.startStubbing();
        mocks.when(securityHandlerMock.isCurrentUserAllowedToEnter()).thenReturn(true);
        mocks.stopStubbing();        

        // When
        House standardHouse = new House(securityHandlerMock);
        standardHouse.openDoor();

        // Then
        System.assert(standardHouse.isDoorOpen, 'The door should be open.');
        ((SecurityService) mocks.verify(securityHandlerMock, 1))
            .isCurrentUserAllowedToEnter();
    }
}

At glance, you’ll notice that I have removed all the data creation, but also the “System.runAs sentence. We no longer depend on any underlying data. Let’s see what we have done step by step.

First, in the “Given” block, we have created an instance of the ApexMocks engine fflib_ApexMocks. Then we have used it to produce a stubbed version of the SecurityService. This is the SecurityService securityHandlerMock = (SecurityService)mocks.mock(SecurityService.class);. That’s all the magic we need. If you don’t know what a stub is, we can say that it is a fake version of class that responds and captures behavior on demand. Said differently, we have just created a custom version of the SecurityService that will behave as we want.

Now, by mocks.startStubbing(); we tell the framework to start recording the behavior we are going to dictate. If you are one of the ones that need to understand the internals, the Salesforce Stub API documentation will be very revealing for you to understand this and the previous paragraph, but I recommend you to leave it for later on.

As the “recording” is now on, we can use the when method to set behavior on any method we want. So the sentence mocks.when(securityHandlerMock.isCurrentUserAllowedToEnter()).thenReturn(true); means that we all telling the mocked version of the SecurityService class to return true when the isCurrentUserAllowedToEnter method is invoked.

Watch out here! Don’t forget to stopStubbing to tell the framework you have finished your recording. Otherwise, it will “think” that you are still setting the behavior and won’t behave as you just instructed it. Trust me, that will puzzle you some time.

The next couple of lines don’t have any mistakes. Finally the instance of the House class gets created, but it receives the Stub instead of the “real” instance. The openDoor method will be actually invoked. You can check the test coverage afterwards to verify all the lines are covered, but you’ll also see that the SecurityService is not covered at all. 

Last but not least, you must verify the results. The obvious is to check the isDoorOpen flag has the value you expect. But with ApexMocks you can also check that the underlying class has been invoked once and only once. mocks.verify does exactly that. The ApexMock framework records every call to all the subbed methods. That’s something you couldn’t do without the framework!

Thoughts and considerations

For the devs that never used the techniques described in this article it is hard to change their mindset at the beginning. It happened to me too! Some may argue that, with these, we are not really testing the code, because we are replacing the internals. But the truth is that we are doing it better. Think that we inject any use case we want with the “startStubbing” methods, so our testing capabilities are much wider. Also think that the classic unit tests need to know too much about the implementation of the tested method as they need to create the data that it is expected to consume.

There will be methods you must test using real data. If you have structured your code in layers, a good example is the Selector one. You cannot mock the DB queries if what you are testing is specifically that! You can though mock the selector layer when testing other methods that depend on that and by the way, enforce edge cases that would be hard or impossible to recreate in test. Also, don’t forget it is essential to have a minimum set of integration tests.

Before closing the article, let me say that we have seen here a very limited number of the possibilities the ApexMocks framework offers. They will cover most of your needs though. But the more you progress and apply mocks, the more tools you’ll need and discover. The readme file of the official gitHub repository contains a god set of links you may want to visit at some point. 

Bonus

ApexMocks was originally crafted by Paul Hardaker and backed by FinancialForce making developing in Apex a much more delightful experience for everyone. And we all thank them! Also there are several ApexMocks advocates and contributors that keep the framework alive and teach about all its capabilities around the world. 

I leave you my favorite ones next. Feel free to add them to you ApexMocks bookmarks!

 


Your email address will not be published. Required fields are marked *