I recently tackled unit testing my AFNetworking client classes, which use block based callbacks, stubbing out block callbacks took some trial and error so is worth of a blogpost.
Take the example method:
How would you go about mocking/stubbing this method call? One way is to use OCMock expectations. In your unit test setUp:
1 2 3 4 5 6 7 8 9 10 11 12 13
In the actual test, you can change the value of
stubMessagesPayload and assert different behaviour. You’ll also notice the block argument is located at index 2, from the documentation:
Indices 0 and 1 indicate the hidden arguments self and _cmd, respectively; these values can be retrieved directly with the target and selector methods. Use indices 2 and greater for the arguments normally passed in a message.
The other issue you may face is how to get your class to actually use the mocked version of your object. The code under test may look like this:
1 2 3 4 5
The only way to stub a class method is via swizzling, which can get messy. The alternative is dependency injection, whereby you expose object dependencies using properties or constructor varaibles. Then they can be swapped more easily at runtime, so if the
AFRedditAPIClient object where a public property, and
RCMessageClient were the class i wanted to test, expose the dependency using a property and in the test asign it to the mock object:
1 2 3 4 5 6
And the implementation changes to refer to that property instead of the class method:
1 2 3 4 5