Using OCMock with Swift

Adem Atalay
Mac O’Clock
Published in
4 min readMay 3, 2020

Unit testing is one of the most important parts of software development. It is basically testing small parts of the codes individually by using public interfaces of objects. While developing an object, other objects, modules or libraries are used as dependencies and they are injected to the code to be utilised.

In unit testing, only the developed code which is called as System Under Test (SUT) should be tested and mock version of other dependencies should be injected as a black box. Creating a mock version of an object can be achieved by two ways

  1. Manual mocking is creating a dummy object by inheriting from the original object and overriding public interfaces or creating a dummy implementing of a protocol. This is the widely used method in Swift unit tests. However, the number of dummy implementations may grow too much.
  2. In memory mocking is creating a mock object of a class or protocol and configuring it on place. This is the widely used method in Objective-C (ObjC) unit tests. The objects can be disposed when test is done, thus there is no need for dummy implementations.

OCMock is a great library for mocking in ObjC. It has a lot of features which can fulfil almost every need while testing codes. It can create mock objects of classes or protocols, predefine the return values of the public interfaces or capture the arguments sent to methods etc.

OCMock uses Swizzling technique to create mock objects and Swizzling can only be used in ObjC which this is one of the reasons why we cannot to use it with pure Swift.

OCMock returns id from its methods because, in ObjC world, the most powerful generic is id where we can send any call invocation on to it. This means ObjC is not a very type-safe language and this is turned into a benefit while mocking. However, Swift is strict on type safety and this is another reason why we cannot use it with Swift.

ObjC supports lightweight generics which is an adaptation of header files for different types and using the most powerful generic id underneath. This can be utilised to overcome the type-safety problem. By that way, ObjC objects, protocols and @objc tagged Swift protocols can be mocked and used in Swift unit tests.

A sample header definition can be like the one shown on the left. This object will create a mock object of the given type and pre-define the object’s behaviours.

Implementation of the class will use OCMock methods to create mock objects or stub methods as shown on the left. As seen the return types are id since ObjC implementation files cannot use generic definitions. However, since the return type of the methods is defined with generic types in the header file, this manipulation will trick Swift to use that as desired types.

Now let’s assume a UIViewContoller is injected into an object and the object calls view property in the implementation like below.

If a mock object is injected into this method without any expectation, the test would fail with invalid invocation with unexpected method error as follows.

Here the method call should be expected to make the test valid as follows

The mock view controller returns nil value for its view property and the test passes. Now, let’s test nonnull case of this method. To do that, our mock object should return a view when view property is called and this can be done by using the andReturn method of our wrapper.

As seen on the above test, the mock object returns an empty view for the property and test passes with this mock value.

Injecting a dependency can be done in many ways and the most common ones are direct injection of objects and injection of protocols. The latter brings a lot of benefits into codes and helps developers to follow SOLID principles. A mock implementation of an ObjC protocol can be achieved by OCMock with a similar way to class mocking and unfortunately, Swift protocols cannot be mocked as well. However, the good news is that while there is no way to mock a Swift class, @objc tagged Swift protocols can be mocked in the same way. So, choosing dependency injection by protocols makes development code more testable in this way.

This story contains very basic use cases and this can be extended too much to cover most of the OCMock features such as static method mocking, method expectation with any arguments, gathering arguments from invocations etc. I hope it helps.

Thank you for reading and happy testing.

--

--