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 GitHub repository ūüôā


Introducing ApexMocks Framework

The goals I set myself in creating a mocking framework for the 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)

Behaviour Driven Development on the platform

Coming from an Enterprise Java background to the world of development, two things I have found myself missing most of all (putting to one side the lack of a debugger!) are a good mocking framework and built-in support for dependency injection.

Anyone familiar with the practice of Behaviour Driven Development and wanting to practice this when writing Apex code has no doubt found themselves missing exactly the same things.

So I decided to see what would be possible on the platform, given the limitations of Apex.

(For those interested in the DI aspects of all of this, Jesse Altman, MVP, has done some great work in this area

Why Behaviour Driven Development?

Test Driven Development as a practice has been around for a good while now. It seems to be one of those things which divides opinion quite strongly! Personally I have found it to be a really great way to help me design code which attempts to adhere to SOLID principles. Applying TDD in this way puts the focus very clearly on the driven aspect of TDD, using tests to help drive the design of the system. And the key thing we want to design is the behaviour of the system, which leads nicely onto BDD. BDD re-emphasises the behavioural aspect of TDD, in that any tests we do write should be testing behaviour and never implementation.

Two Approaches to Unit Testing

My thinking in this area is heavily influenced by GOOS as it is affectionately known by its fans. In very simplistic terms, if we view any system as being comprised of components which send messages to each other to achieve the behaviour of the system, one of the key things we will want to design and test are the components and the messages they send to each other. This approach to TDD is known as ‘Mockist’ as opposed to what is sometimes called a ‘Classicist’ approach, which puts the emphasis on asserting the state of the system rather than behavioural interactions. (This is not without controversy itself. Anyone who has read¬†Mocks Aren’t Stubs by Martin Fowler will know what I mean, his article is very much worth reading if you’ve not done so already. One of the authors of GOOS replied to this here State vs Interaction Based Testing.)

I think in reality both approaches – mockist and classicist – are valid and the key thing is knowing how and when to apply which one, and that only comes with experience.

Mock objects really help an outside-in approach to BDD – most of the time I find myself using a mocking approach to discover interfaces for classes that don’t yet exist. The mock objects I use whilst applying BDD at one layer of the system help me to discover the responsibilities of the next layer in.

One of the objections to this approach you might here is something along the lines of ‘but I really want to design by contract and design all my interface definitions upfront’. Using this approach does not mean you haven’t thought through the high level¬†architectural design of the system, but it can really help clarify your thinking at the detailed component level.¬†(Uncle Bob posted an interesting discussion on this recently)

Guiding design is one of the (main?)¬†reasons to use a mocking framework, so I am going to assume you’ve done your own thinking about this¬†and would like to try that out on the platform.