ApexMocks: How Does It Work?

Last week, I wrote an article about writing real unit tests on the Force.com platform for the first time using ApexMocks. What Paul Hardaker (@comic96) has been able to do using ApexMocks is a big step for Force.com developers. We now have the capability of testing singular units of code quickly. I have already discussed why this is useful, but how does it all work?

Powered by Dependency Injection

ApexMocks heavily utilizes dependency injection, or the idea that you pass dependencies into a class through some means, typically the constructor. Let’s look back at our final set of code from last time:

MyController

public class MyController{
    private MyInterface myImplementation;
    public Integer valueOne{get;set;}
    public Integer valueTwo{get;set;}
    
    public MyController(MyInterface myImplementation){
        this.myImplementation = myImplementation;
    }
    
    public Integer calculatedTotalValue(){
        return myImplementation.calculateValues(valueOne, valueTwo);
    }
}

MyControllerTest

@isTest
public class MyControllerTest{
    public static testMethod void testCalculateValues(){
        fflib_ApexMocks mocks = new fflib_ApexMocks();
        MyInterface mockMyService = new MockMyService(mocks);

        mocks.startStubbing();
        mocks.when(mockMyService.calculateValues(5, 3)).thenReturn(8);
        mocks.stopStubbing();

        Test.startTest();
        MyController controller = new MyController(mockMyService);
        controller.valueOne = 5;
        controller.valueTwo = 3;
        Integer totalValue = controller.calculatedTotalValue();
        Test.stopTest();
        
        System.assertEquals(8, totalValue, 'The service should return 8');
    }

	private class MockMyService implements MyInterface{
		private fflib_ApexMocks mocks;

		public MockMyService(fflib_ApexMocks mocks){
			this.mocks = mocks;
		}

        public Integer calculateValues(Integer valueOne, Integer valueTwo){
            if (mocks.Stubbing){
                mocks.prepareMethodReturnValue(this, 'calculateValues', new List<Object> {valueOne, valueTwo});
                return null;
            }else{
                mocks.recordMethod(this, 'calculateValues', new List<Object> {valueOne, valueTwo});
                fflib_MethodReturnValue methodReturnValue = mocks.getMethodReturnValue(this, 'calculateValues', new List<Object> {valueOne, valueTwo});

                if (methodReturnValue != null){
                    if (methodReturnValue.ReturnValue instanceof Exception)
                    {
                        throw ((Exception) methodReturnValue.ReturnValue);
                    }

                    return (Integer) methodReturnValue.ReturnValue;
                }
            }

            return null;
        }
	}
}

MyInterface

public interface MyInterface{
	Integer calculateValues(Integer valueOne, Integer valueTwo);
}

MyService

public class MyService implements MyInterface{
    public Integer calculateValues(Integer valueOne, Integer valueTwo){
        return valueOne + valueTwo;
    }
}

In the above example, MyController has a dependency of MyInterface. Now, we could have just easily and validly written our controller like:

public class MyController{
    private MyService myImplementation;
    public Integer valueOne{get;set;}
    public Integer valueTwo{get;set;}
    
    public MyController(){
        this.myImplementation = new MyService();
    }
    
    public Integer calculatedTotalValue(){
        return myImplementation.calculateValues(valueOne, valueTwo);
    }
}

The problem here is that the MyController needs to know what service is being used. This type of architecture provides poor flexibility. By removing that dependency and using an Interface and injecting an instance of a class implementing that interface, we have provided the flexibility to write any number of service implementations. You can see the usefulness of this type of approach in something like a payment service.

Injecting Mocked Dependency

By utilizing dependency injection, we can create our own service purely for testing. In our unit test above, we create our own mocked service as part of the unit test. Lines 21-48 show our MyMockService and how it implements the necessary interface. This allows us to completely bypass the actual service calculations and run our own code. This is where ApexMocks begins to come into play. Specifically, notice how we inject an instance of fflib_ApexMocks into MyMockService at line 5. To allow our class to compile, we have to adhere to the interface. This forces us to add a calculateValues(Integer valueOne, Integer valueTwo) method at line 28. You can see in the method that the fflib_ApexMocks instance we injected earlier is now heavily utilized. One of the beauties of open source software is that you can really review the code you are interacting with. In this case, I heavily suggest you to review the fflib_ApexMocks class, fflib_MethodReturnValue class, and fflib_MethodReturnValueRecorder class as they are all heavily utilized in our example.

Our calculateValues method is written so that it:

  • Records the method and result when stubbing is turned on – lines 29 – 31
  • Retrieving the mocked value when stubbing is turned off – lines 33-46

The way stubbing works is that it essentially stores the mocked parameters and result in a Map on the fflib_MethodReturnValueRecorder class (check the prepareMethodReturnValue method). This is saved (and ultimately returned as) an instance of the fflib_MethodReturnValue class. When stubbing is turned off, the method returns the fflib_MethodReturnValue class from the Map. Note this instance of the fflib_MethodReturnValueRecorder lives on the fflib_ApexMocks instance of MyMockService that we pass in all the way back at line 5 in MyControllerTest. This allows us to make sure it all stays in memory as our test runs.

Mocks in Action

Let’s inspect the actual unit test now. Lines 7-9 is where we actually run the stub out our mock. We turn on stubbing at line 7. This is important because it needs to be turned on to put our mocked value into our Map when calculateValues() gets mocked out at line 8. When line 8 is executed, it actually runs the MockMyService.calculateValues() method as parameter of the when() method. This will run through lines 29-31 on MyMockService, creating a reference in the Map on the fflib_MethodReturnValueRecorder. As part of this as well, the fflib_MethodReturnValue generated from the when() method gets its value set as part of the thenReturn() method. This is then set on the fflib_ApexMocks instance. Following immediately after this step, line 9 turns stubbing back off. This allows the controller to then call the MyMockService.calculateValues when MyController.calculatedTotalValue() is called at line 15 and simply return the value we set at line 8. It completely removes the need to run MyService code at all because it is simply never used.

True Unit Tests

I hope this helped reinforce the point that ApexMocks truly allows you to unit test. You will only test MyService when you write unit tests for it. It will not be part of the MyController test because the code simply never runs. Now, for this simplistic example, this approach is obviously overkill, but hopefully you can see the power something like this can provide. You don’t need to generate the entire data model, allowing all of the triggers, workflow rules, etc to run. Mock those service calls and enjoy fast, reliable unit tests.

Conclusion

This is only a small piece of what ApexMocks has to offer. It is a complex library that does some really cool stuff. Take some time to go through the code to see what is possible and how it works. Next week I’ll focus on helping you set up ApexMocks in your own org. Enjoy!

12 Responses to “ApexMocks: How Does It Work?”

  1. Mahesh Adi
    June 24, 2014 at 10:03 am #

    Great post Jesse!

  2. Ringo
    June 25, 2014 at 9:59 pm #

    Hi,

    Could you please explain a bit more why we have to implement method calculateValues(…) in MockMyService class.

    • June 26, 2014 at 7:23 am #

      Hey Ringo,

      We need to implement that method because that is the code ApexMocks actually runs rather than your actual service implementation. Notice how MockMyService implements our interface as well. This does tow things. It forces our class to match the public methods on the interface and it allows us to use dependency injection to pass this implementation into our controller rather than the actual code we run in normal scenarios. By mocking out this method, we control what that method returns.

      The good news is the author of ApexMocks actually has a tool you use to just generate that code. In most scenarios, you will never have to do anything with that piece of code. I was personally interested in how it actually worked, so that is why I wrote this article to explain more on how this is all possible. Most people will never need to worry about all of this if they are just using ApexMocks.

  3. Tyler
    March 12, 2015 at 1:03 am #

    Hi Jesse,

    I’m having some issues with a mock test. I have setup all of my interfaces (correctly I assume as all integration tests work as expected). I am finding that even though I am stubbing my selector class nothing seems to be returned. Here is a pastebin to view the code: http://pastebin.com/ACJNH8wF

    when the following line in my domain class is called:

    Map newAccountMap = new Map(AccountsSelector.newInstance().selectById(newAccountIds));

    newAccountMap is always null (I have debugged and ensured that newAccountIds = myAccounts[1].Id)

    Any help you can provide would be most appreciated. Thanks!

    • March 12, 2015 at 9:31 am #

      My guess would be that you need to add a mocked call for the SObjectType() method in the SelectorMock. The problem is that the Mocks class also mocks that method, so it is causing issues when actually being called in the code. Try adding something like this to line 33:

      mocks.when(selectorMock.sObjectType()).thenReturn(Account.SObjectType);

      • Tyler
        March 12, 2015 at 11:28 am #

        You’re a genius! That worked like a charm. Thanks for the help, it’s really appreciated.

  4. Alex
    April 22, 2015 at 12:10 pm #

    Hi Jesse,

    I am new in Salesforce and trying to use ApexMock. It’s a great solution for Apex and you did a great job explaining on this article. However, by following your example, I couldn’t make the connection about the usage of a mocked method and the coverage of the real one by the unit test.
    Could you clarify a little more about the code coverage? Or if you are explaining that in another article, could you share the link?

    Anyways, thank you by sharing all these knowledge here.

    • Alex
      April 24, 2015 at 4:33 pm #

      Hi Jesse,

      Never mind. I could go a little further on the understanding of the mock implementation and see the coverage of code as well as better understand the usage of start and stop stubbing.
      Thanks once more for your article and contribution with this mock framework for Apex.

  5. Haseeb Khan
    April 4, 2016 at 3:14 pm #

    Hi Jesse,

    I am working on a project in which we need to test an APEX REST Service in such a way that no actual data is created in Salesforce during the testcases execution. I am new to APEX Development.

    Searching on the web took me to fflib-apex-mocks library which seems to serve the purpose of avoiding the usage of actual test data inserted in the database for testcases execution. I have installed fflib-apex-mocks and fflib-apex-common in my sandbox environment.

    So far, I am not able to find out a step-by-step guide as what I need to do if I want to test my existing Salesforce Objects at a unit level and how can I test my APEX Rest Service? From looking at the fflib-apex-common-samplecode it seems that I need to define classes for my Salesforce objects, I am not sure if I am getting this right.

    At a higher-level, below are my questions at a higher-level:

    1 – I have a Student__c Object already defined in Salesforce, it has some triggers for insert and update which has checks for various fields and I want these triggers to fire when I try an insert or update for the mock object. I want to develop testcases for that, what do I need to do? How do I start?

    2 – I have an APEX Rest Service which gets a collection of Teacher__c objects converted to JSON based on the id of a Student__c object provided to it as a query parameter. I have previously developed testcases for APEX Rest Service but that didn’t involved actual objects usage but my current scenario is different as it involves usage of actual objects.

    Can you please help me out in getting started?

    Thanks,

    Haseeb Khan

Trackbacks/Pingbacks

  1. ApexMocks: Setup | Jesse Altman - October 7, 2014

    […] my last two posts, I covered why using ApexMocks is beneficial and how ApexMocks works. In this post, I will cover how to deploy ApexMocks into one of your orgs. In order to deploy […]

  2. One Batch Apex to rule them all (Part II) – versiononefirst__c - July 20, 2016

    […] miss the opportunity to check the Jesse Altman’s introduction too, who will be doing a talk about this at Dreamforce! “Speed Up and Simplify Unit Tests […]

Leave a Comment