views:

241

answers:

2

Hello!

I want to test a piece of code that uses network (the NSURLConnection class, to be specific). The code (let’s call it NetworkManager) looks a bit like this:

- (id) buildConnection
{
    // some more code and then:
    return [NSURLConnection …];
}

- (void) startNetworkSync
{
    id connection = [self buildConnection];
    //…
}

In the unit test I would like to get rid of the networking, ie. replace the NSURLConnection object by a mock. How do I do this?

I’ve tried creating a partial mock of the NetworkManager that would replace the buildConnection method by a stub. The problem is that partial mocks as done by OCMock only stub messages from the outside world – sending buildConnection from the startNetworkSync invokes the original method, not the stub.

I have also tried monkey-patching the NetworkManager class through a category. This works, I can easily override the buildConnection method by other code and replace the real NSURLConnection with a stub. The problem is that I found no simple way I could get the stubbed connection in the test – the connection is a private part of the NetworkManager.

Then I could subclass the NetworkManager, override the buildConnection method and add an instance variable plus an accessor for the created connection. This seems like a lot of code, though.

How would you solve this? I am looking for a solution that keeps the NetworkManager class design clean and does not require much magic nor much code in the test.

+2  A: 

This is the kind of thing dependency injection is designed to solve; if you use startNetworkSyncWithConnection:(NSURLConnection*) instead you can easily test the method with a mock connection. If you don't want to change the API for your clients you could even keep startNetworkSync as a wrapper that does nothing but call that new method with [self buildConnection] as the argument.

smorgan
OK, I’ve more or less done it this way. The clients know nothing about network, they only send and receive data, but I’ve added the method to inject a ‘foreign’ connection to the process, which helps in testing. Thanks.
zoul
+2  A: 

I modified OCMock to support real partial mocks. You can find the code at http://github.com/mmangino/OCMock/tree/master

Mike

Mike Mangino
Thanks. I’ve already solved the problem, but real partial mocks would be handy. Any chance of merging the code with the vanilla OCMock?
zoul
Yes, the author of OCMock is in the process of merging. He's going to try to make it even cleaner during the merge.
Mike Mangino