ApexMocks Improvements – exception stubbing, inner interfaces and mock base classes

A new version of ApexMocks and the associated mock class generator will be released to GitHub later today. This will bring various improvements to your life as an Apex mockist!

Support for Exception Stubbing

Sometimes when writing a unit test it is helpful to be able to stub an exception to be thrown. You can now do this using the new thenThrow() and doThrowWhen() methods:

mocks.when(mockList.get(0)).thenThrow(new MyException('Stubbed exception.'));

((fflib_MyList.IList) mocks.doThrowWhen(new MyException('Stubbed exception.'), mockList)).clear();

The doThrowWhen syntax is necessary when you want to stub a void method to thrown an exception. Please see the fflib_ApexMocksTest class for examples of unit tests using these features.

Inner Interfaces

The apex-mocks-generator now supports inner interfaces, for example:

public class fflib_MyList implements IList
{
    public interface IList
}

Simply specify the inner interface in your interfaces properties file:

fflib_MyList.IList=Mockfflib_MyList

Base class support for Mocks

If you would like a generated mock class to extend a base class, you can use the following notation in your interfaces properties file:

IOpportunities=Opportunities:BaseOpportunities

Here we are saying that the IOpportunities interface should create a mock class named Opportunities which will extend the BaseOpportunities class:

public class Opportunities extends BaseOpportunities

Improved Code Generation

The apex-mocks-generator has been enhanced to create less generated code resulting in slimmer, more efficient mock classes. Please use version 3.1.0 to take advantage of this and the above features.

Advertisements

New Improved apex-mocks-generator

An improved version of apex-mocks-generator will shortly be released to GitHub. This greatly simplifies the generation of mock classes for your interfaces.

Interfaces are now specified via a properties file using key-value type syntax <interface name>=<mock class name>

ICreditCardProcessor=CreditCardProcessor
TaxEngine=TaxEngineImpl

Define interface names as you like – use an ‘I’ prefix at your discretion. Choose whatever mock class name you like.

The new apex-mocks-generator will parse your interfaces file and generate a single ‘mocks’ class for you which will contain mock class definitions for all of the interfaces you specified.

As before you can use the generator via Java or ant. The basic format is the same, apex-mocks-generator needs to be told about:

  1. sourcePath – where your apex source files reside, e.g. “src/classes”
  2. interfaces – the properties file containing the interfaces you want to mock, e.g. “interfaces.properties”
  3. mocksClassName – the class name for the class which will contain all your mock classes, e.g. “Mocks”
  4. targetPath – where you want the generated mocks class to reside

Generating a Mock Implementation Using Command Line Java

Simply download the latest apex-mocks-generator JAR from GitHub, then run the following from your terminal:

java -jar apex-mocks-generator-3.0.1.jar <sourcePath> <interfaces> <mocksClassName> <targetPath>

e.g. java -jar apex-mocks-generator-3.0.1.jar src/classes interfaces.properties Mocks src/classes

Here we are generating a Mocks class into the same folder as our other Apex classes, src/classes.

Generating a Mock Implementation Using ant

To generate a mock implementation using ant, add the following target to your build.xml file, replacing the <path-to-apex-mocks-jar>:

<target name="generate.apex.mock">
    <java classname="com.financialforce.apexmocks.ApexMockGenerator">
        <classpath>
            <pathelement location="<path-to-apex-mocks-jar>.jar"/>
        </classpath>
        <arg value="${sourcePath}"/>
        <arg value="${interfaces}"/>
        <arg value="${mocksClassName}"/>
        <arg value="${targetPath}/>
    </java>
</target>

Then from your terminal run:

ant generate.apex.mock -DsourcePath="src/classes" -Dinterfaces="interfaces.properties" -DmocksClassName="Mocks" -DtargetPath="target/classes"

Here we are generating a Mocks class into a target folder which we are using for all our generated source files.

ApexMocks Supported Features

Currently the ApexMocks framework supports the following:

  • verify a method was called with the correct arguments
  • verify a method was called n number of times
  • verify a method was never called
  • stub a method call with a particular set of arguments to return a particular value
  • stub a method call with a particular set of arguments to throw a particular exception

Caveats (given I developed ApexMocks in my free time):

  • somewhat stating the obvious, I haven’t tested ApexMocks with every possible variant of method you could write in Apex
  • apex-mocks-generator has not been tested against all possible variations of interface method definitions – it is possible it may fail when generating a mock class for some methods – if that happens please contact me. (Or if you are very brave edit the generated mock code directly.)

Please contact me @comic96 on Twitter or via this blog to feedback or ask questions. Or fork the GitHub repo. Thank you!

Stubbing Dependencies in a Unit Test

Last time we saw how to verify the behaviour of our components using verify() based unit tests.

The other beauty of a mocking framework is that it allows you to stub dependencies so you can focus on unit testing the logic of the component you are working on, without worrying about having to use real versions of dependencies.

For example, suppose you are creating a component like a VisualForce controller extension, which uses a service class to interact with business logic (see Apex Enterprise Patterns).

Traditionally, to unit test your VF controller, you would need to create records and insert them in the database, so that your service class will then load the necessary data when it is used by the controller extension.

But with the ApexMocks framework, you can stub your service class to return whatever data you like – and it doesn’t have to even exist on the database.

This means less setup for your test and also the test will run much more quickly because it doesn’t have to interact with a real version of your service class, which in turn means no interaction with the database. So we can write DML free unit tests.

To give a simple example, say we want to stub a CarService to return some data such that we can test a CarControllerExtension:

@isTest
private class CarControllerExtensionUnitTest
{
    @isTest
    static void bookingCarServiceShouldTakeUserToServicingPage()
    {
        // Given
        ApexMocks mocks = new ApexMocks();
        CarService.ICarService mockCarService = new MockCarService(mocks);

        // Create our custom object but don't insert it into the database
        Car__c car = ObjectBuilder.createCar().withName('Audi').

        // Use the ApexMocks IDGenerator to create a dummy Salesforce Id for our object.
        // In reality we would probably get our ObjectBuilder to do this for us.
        Id carId = IDGenerator.generate(Car__c.SObjectType);
        car.Id = carId.

        // Use ApexMocks to stub the return value for the service's getCar() method
        mocks.startStubbing();
        mocks.when(mockCarService.getCar(carId)).thenReturn(car);
        mocks.stopStubbing();
        
        // When
        CarControllerExtension carControllerExtension = new CarControllerExtension(mockCarService);
        PageReference carServicePageRef = carControllerExtension.bookCarService(carId);

        // Then
        System.assertEquals('myExpectedPageRef', carServicePageRef.getUrl());
    }
}

Anyone familiar with mockito syntax should recognise the when() call immediately, apart from the startStubbing() and stopStubbing() calls.

In this test we have also used an ObjectBuilder with a fluent API for creating our test object, and the ApexMocks IDGenerator to create a fake Salesforce Id.

ApexMocks frees you up to stub any of your Apex classes which should transform the way you are able to write unit tests for the Force.com platform.

The key thing to focus on is testing the logic of your class/component, and to use mock versions of it’s depdendencies where appropriate. But don’t mock yourself into a corner – mocks are very powerful, but can be overused.

 

Writing Behaviour Verification Unit Tests

Last time we saw how to add a mock implementation of our component to our unit test class using the apex-mocks-generator tool.

Now we have everything in place to verify the behaviour of our components in our unit test.

So to take an example, say we want to verify that a BillingService component interacts correctly with a CreditCardProcessor component. To do this we can write a behaviour verification unit test like this:

@isTest
private class BillingServiceUnitTest
{
    @isTest
    static void chargingCustomerShouldProcessCreditCardPayment()
    {
        // Given
        ApexMocks mocks = new ApexMocks();
        CreditCardProcessor.ICreditCardProcessor mockCreditCardProcessor = new MockCreditCardProcessor(mocks);

        Order order = new Order();
        // fill in order details
        order.Id = IDGenerator.generate(Order.SObjectType);

        // When
        BillingService billingService = new BillingService(mockCreditCardProcessor);
        billingService.chargeCustomer(order);

        // Then
        ((CreditCardProcessor.ICreditCardProcessor) mocks.verify(mockCreditCardProcessor)).processPayment(order);
    }
}

Anyone familiar with mockito syntax should recognise the verify() immediately, apart from the cast. Apex has its limits!

The important thing here is the the ApexMocks framework is going to ensure that the correct method on the CreditCardProcessor was called with the correct arguments, when the BillingService charges a customer.

Notice that we didn’t need to insert the Order object into the database, so this test runs very quickly. We also used the ApexMocks IDGenerator to generate a fake Id for the Order object.

Using apex-mocks-generator to create mock class definitions

Last time we saw how to define a component interface such that we could use a mock version of a component in our unit tests.

In order to either verify or stub any given component, we need a mock version of the component which knows how to communicate with the ApexMocks framework.

It would be pretty laborious (and boring!) as a developer if we had to hand-write the mock implementations of our components all the time, so the ApexMocks framework provides a command line tool which will create and add mock class definitions for you.

Having created the component interface definition, you can add a mock implementation of your interface to your unit test class using the apex-mocks-generator. You can either do this via Java or ant. The basic format is the same, apex-mocks-generator needs to be told about:

  1. sourcePath – where your apex source files reside
  2. testClassName – the class to which you want to add the mock
  3. mockClassName – the implementation class name of the component you want to mock
  4. interfaceName – the interface within the implementation class you want to mock

Generating a Mock Implementation Using Command Line Java

Simply download the apex-mocks-generator JAR from GitHub, then run the following from your terminal:

java -jar apex-mocks-generator-2.0.5.jar <sourcePath> <testClassName> <mockClassName> <interfaceName>

e.g. java -jar apex-mocks-generator-2.0.5.jar src/classes BillingServiceUnitTest CreditCardProcessor ICreditCardProcessor

Generating a Mock Implementation Using ant

To generate a mock implementation using ant, add the following target to your build.xml file, replacing the <path-to-apex-mocks-jar>:

<target name="generate.apex.mock">
    <java classname="com.financialforce.apexmocks.ApexMockGenerator">
        <classpath>
            <pathelement location="<path-to-apex-mocks-jar>.jar"/>
        </classpath>
        <arg value="${sourcePath}"/>
        <arg value="${testClassName}"/>
        <arg value="${mockClassName}"/>
        <arg value="${interfaceName}"/>
    </java>
</target>

Then from your terminal run:

ant generate.apex.mock -DsourcePath="src/classes" -DtestClassName="BillingServiceUnitTest" -DmockClassName="CreditCardProcessor" -DinterfaceName="ICreditCardProcessor"

Using a top-level Mocks Class

If you want to keep all your mock class definitions in a single top-level class file (rather than as inner classes in your unit test), just create something like a Mocks class in your Salesforce project and pass Mocks as the testClassName when  you generate a mock. This could aid reuse if more than one test wants to use any given mock class.

In the next post we’ll see how to start writing unit tests using ApexMocks.

Simple Dependency Injection

To start using the ApexMocks framework, you first need to take a Dependency Injection approach to writing your software. Dependency Injection is one way of achieving a loosely coupled, highly cohesive design for your code.

Personally I prefer constructor injection (as opposed to setter injection – Constructor Versus Setter Injection).

At it’s simplest level all this means is that you pass a given class its dependencies via its constructor. In order to facilitate robust production code and the ability to inject mocks I settled on this pattern:

public class MyClass
{
    private DependencyA.IDependencyA m_dependencyA;
    private DependencyB.IDependencyB m_dependencyB;

    public MyClass()
    {
        this(new DependencyA(), new DependencyB());
    } 

    @testVisible
    private
    MyClass(DependencyA.IDependencyA dependencyA, DependencyB.IDependencyB dependencyB)
    {
        this.dependencyA =dependencyA; this.dependencyB =dependencyB;
    }

The ‘real’ production code creates MyClass via the normal default constructor, which still executes the private testVisible constructor, passing in real instances of the dependencies.

The crucial thing is, this frees us up and allows our test to construct MyClass via the private constructor passing in mock versions of the dependencies.

@isTest
private class MyClass
{
    @isTest
    static void my_first_apex_mocks_test()
    {
        // Given
        ApexMocks mocks = new ApexMocks();
        DependencyA.IDependencyA mockDependencyA = new MockDependencyA(mocks);
        DependencyB.IDependencyB mockDependencyB = new MockDependencyB(mocks);

        // When
        MyClass myClass = new MyClass(mockDependencyA, mockDependencyB);
    }

We can then verify that MyClass interacts correctly with its dependencies by writing behaviour verification unit tests.

And we can also stub out the dependencies using when() style dependency stubbing.

This approach even allows us to write DML free tests that never even touch the database, and consequently execute very quickly!

Next time we’ll see how to use the apex-mocks-generator tool to create mock implementations of our component interface.

ApexMocks Framework Tutorial

The next series of posts will form a basic tutorial series explaining how to use the ApexMocks framework in detail. The things we will cover are:

  • Simple dependency injection
    • Defining your component interface
    • Defining your implementation class
  • Using apex-mocks-generator to inject mock dependency classes into your unit test class
  • Writing behaviour verification tests
  • Writing tests which stub dependencies

 

Stringless mocking

When I first started working on ApexMocks, the easiest path to take was to use strings when stubbing and verifying. For example:

mocks.when(myList, 'get').thenReturn('someValue');

Here we are stubbing the ‘get’ method of the MyList class to return our stubbed value. Notice that we are specifying the method to stub via a string parameter to the call to the mock framework when() method.

mocks.verify(ApexMocks.NEVER, myList, 'add');

Here we are verifying that the add method of the MyList class was never called. Again notice that we have specified the method to verify as a String – ‘add’.

Whilst this was the easiest path to take, it’s less than ideal for a number of reasons:

  • it’s error prone – I can easily make a typo in the method argument ‘adf’ instead of ‘add’ for example
  • as an API it’s a bit on the ugly side, the test code is not as elegant and readable as it could be
  • it makes solving the problem of stubbing and verifying method arguments more difficult
  • we’re not making best use of the Apex compiler – if we could call the real methods, we get all the benefits of our test code being compiled properly!

So next time we will start to use the latest version of the ApexMocks framework which allows us to use real method calls when stubbing and verifying behaviour.

We’ll see how to define the component interface we want to stub or verify, how to auto-generate and inject a mock implementation of our interface into our unit test class, and finally how to write ApexMocks unit tests.

And yes – I’ll make the mock framework itself available via our FinancialForce.com GitHub repository 🙂

Introducing ApexMocks Framework

The goals I set myself in creating a mocking framework for the Force.com platform are:

  • minimal impact on production code
  • ease of use
  • mockito style syntax

Mockito is a well known mocking framework for Java development. Personally I love the syntax it provides, it allows for the creation of very readable unit tests.

Any impact on production code should be absolutely minimal, ideally zero. We don’t want to litter production code with instrumentation code, nor do we want to have to write our production code in a way we wouldn’t have done just to use a mocking framework.

Keep in mind mocking makes the assumption we will be using dependency injection, so we also need a simple, light-weight approach for DI too.

So given all of that, the kinds of basic requirements I would envisage for a mocking framework are:

(1) basic when style stubbing

when(myClass, 'someMethod').thenReturn(someValue)

(2) specific argument matching

when(myClass, 'someMethodTakingStringArgument', 'argumentValue').thenReturn(someValue)
when(myClass, 'someMethodTakingIntegerArgument', 1).thenReturn(someValue)

(3) verify style behaviour verification

verify(myClass, 'someMethod’)
verify(myClass, 'someMethod', argumentValues)

(4) exception stubbing

when(myClass, 'someMethod').thenThrow(new MyException())

(5) argument matchers

when(myClass, 'someMethod', anyInteger()).thenReturn(someValue)