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.

 

Advertisements

8 thoughts on “Stubbing Dependencies in a Unit Test

  1. Hello, were you able to work around formula fields? I have some methods that depending on a value of a formula field do some thing or the other. I’m able to mock the query that returns all the values, as I stub it and return the record I created in the test, but i’m not able to populate the formula field to make it work properly. Is there a way to make it works?

  2. Pingback: Counters in Apex Mocks verifications – XoNoX Force

  3. Pingback: Verify call’s order in Apex unit tests – XoNoX Force

  4. Pingback: Answering with Apex Mocks – XoNoX Force

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s