mock_head

Mock Mocks in Apex

I love mocking frameworks. I love the ability to isolate a unit of code so I can make smaller, more coherent tests. I have grown accustom to them during my time with java and I would love to use them with apex. The problem is that mocking frameworks rely heavily on robust reflection, a feature apex sorrily lacks.

Sorry. Lost the happy, but the happy's back!
Sorry. Lost the happy, but the happy’s back!

While we cannot yet simply tell a method to generate a mock class, maybe we can make an approximation. A lightweight class that can be substituted for the real thing when testing a class that relies on it could work in many cases. How to get the mock class in there though, that is the question. While Apex is missing most of the necessary reflection, it is not missing all of it. Enter a little known blog, by a man called Jesse Altman, that goes into dependency injection with Apex. That, my friends, is the foundation of what I will go into here. If you didn’t click the link above, and I don’t know why you wouldn’t have, read the article on dependency injection right now. Seriously, if you go on without reading it I will be disappointed in you.

Are you done? And no lying, I will know. So, I have my classes and custom settings pretty much the same as the one from Jesse’s blog post and will be building from there. The best place to start with a blog post on mocks and unit tests is probably a unit test. The unit test will initially test the the classes as they are.

My service just just calls processPayment on a PaymentInterface, nothing special there. The test inserts a custom setting first, grabs the return value from processOrderPayment and verifies the result. Not too much going on here, certainly not deserving a post. Yet. Lets spice this test up.

Look at that, injecting an inner class from within the test worked just fine too. The problem is that this is a trivial example. Why bother mocking? Let’s make this a bit more complex.

I have changed the interface to have the method getAuthCode and added a string parameter to processPayment. The service now checks for a non null authCode and throws an exception if it is. Our mock has had its methods changed accordingly and now, process payment verifies the parameter passed to it. This is closer to our mocks, but now we have a branch we can only test by adding another mock. Inconvenient indeed. One last change, one last push over the finish line. A new class will get us where we need to go.

This hefty class will let us reuse the same mocks multiple times. I wont break this down line for line but I will summarize it. The command object holds parameters to verify against and return values to… return. The method add call adds the call to a map containing a list of command objects, keyed to the method name being mocked. The calls to a particular method must be mocked in the order they will be run. The method getCall gets the command for a method, verifies the parameters are the same and returns the stored return value. What does this look like in practice? Ask, and ye shall receive.

The mock now extends MockMaker and does nothing more than wrap different calls to getCall. The test methods (yes, now there are two) mock out the calls to the payment service with MockMaker.addCall. We can now use the single mock, injected into the OrderService via the factory, to run multiple tests. This isn’t perfect but for services with call-outs or just very heavy methods, this can be a real help.

4 comments

  1. Peter Friberg says:

    Thanks for sharing Bob!
    Happy to see there are others testing with functionality in focus rather that code coverage 🙂
    I made some “smarter” mockups of webservice calls a year ago that I could “prepare” from my test classes so to mock would return a failure, thus forcing my fault handling code in my classes to be executed. Testing negative behaviour is important as we know 🙂

Leave a Reply

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