Your First Objective-C Unit Test with OCMock

January 4, 2013

I’ve been making a lot of noise about unit testing in Objective-C lately, so I thought I’d put my money where my mouth is and write a primer. This tutorial is going to take you through, step-by-step, how to write your first unit test.

I’m going to be writing tests for an open source 500px iOS SDK I wrote for the company. You can follow along by downloading a tag of the repo I made before writing unit tests. It only has integration tests right now, which we’ll turn off. Open the PXAPI project, click “PXAPI” in the project bar to the right of the run/stop buttons, and click “Edit Scheme”. Select “Test” in the left hand pane and deselect each individual test (but not the top-level “Tests”).

The first thing you need to do when writing unit tests for network code is make a private instance method in the class you’re testing that will create all of your NSURLConnection objects. This is how we will replace real url connection objects with our own, stubbed versions.

We’re adding the custom, private initializer initWithURLRequest:completion: because we only want to test the PXRequest class. The class methods to create ’PXRequest’s are all contained in another file. We’ll test those separately, later.

Great. Let’s write our first test. This will make sure that the start method starts the URL connection instance.

What we’ve done is create a mock connection. It mocks NSURLConnection. We’re going to tell it to expect the start method to be called. We’re making it a “nice” mock so that other methods can be invoked on it, too. You can use the mockForClass: instead, if you want stricter tests.

So now we have a mock NSURLConnection instance that expects start to be called on it. We need some way to “give” this mock object to our requestUnderTest. We’re going to do that using a partial mock. This is a special kind of mock object. We can stub out methods that will be called and replace them with our own return values. Any methods we don’t stub out will be passed onto the original instance.

We’re telling the partial mock that when urlConnectionForURLRequest: is called with any parameter, return mockConnection.

You should read the code from the start, then after “stub”, from the back: “stub ’urlConnectionForURLRequest:’and return ’mockConnection’.”

Now lets run the test.

[partialRequestMock start];

This is the method we want to test. It will call urlConnectionForURLRequest:, which we’ve replaced with our own implementation. Now we want to make sure that calling this method actually called start on the connection. That’s what the last line is for.

[mockConnection verify];

Calling this method verifies that all the expected methods have been called. If they haven’t, your test will fail here.

Let’s do another test. This time, let’s test to make sure our completion block is invoked when there is a failure. First, we need to make sure that the connection:didReceiveResponse: method only calls statusCode on the url response once, since we OCMock only handles each expect call once.

First, we declared a __block variable to record if the completion block is invoked at all. In the completion block, we assert that the arguments to the block are what we expect. Arguably, this could go in its own test depending on how granular you want to test.

Next, we create a mock connection, just like last time, except now we tell it to also expect a call to cancel.

In addition to calling start, we’re also going to manually invoke the NSURLConnectionDataDelegate method connection:didReceiveResponse:. This means we’ll need a response to pass in as the second parameter. That’s where the mockResponse object comes in. We’ll create a mock NSHTTPURLResponse that returns 404 when ask for its status code. This is how we will simulate the connection failure.

That’s it! That’s a basic primer on how to begin unit testing your network code. There is a lot more subtlety to unit testing and I would suggest you check out the OCMock Documentation.