1

I have simple class for perform network stuff. It's a singleton and it encapsulates NSOperationQueue inside it. When class' user calls some method to getting data from network, this class creates proper instance of operation class inherited from NSOperation sets up it and adds to queue for performing. Obviously, that performing is making asynchronously in separated threads. After getting data from network NSOperation inherited object notifies my network class and it notifies interested delegates about data getting finished or error.

Question is, how can I make unit tests for checking network class' logic? Also, I don't actually want to test server side behavior. I just want to replace actual async call to server with mock and predefined answers to after test handlers' behavior. I want to check how are my classes work, not server side. I understand commonly logic for testing stuff like that but I little bit confused with using OCMock for it. Best answer will be code example. I'm using OCUnit and OCMock in my project for unit testing.

Also any articles or github links will be perfect.

Rostyslav Druzhchenko
  • 3,673
  • 3
  • 33
  • 38

2 Answers2

3

If all the asynchronous calls go through an internal method in your class, you can simply create a partial mock on your object and use stub/expect on that method. You can then call the public methods as normal and use the mock to verify that the internal method is called. Using the partial mock stops the real implementation from being called, so no network activity should occur.

As to the other half, the call-backs from the asynchronous operation, simply call the method that would be called directly from your tests, then check that your class does the right thing, either by checking its state with OCUnit asserts, or, if it in turn uses callbacks, with another mock.

Erik Doernenburg
  • 2,933
  • 18
  • 21
1

So I know this is regarding OCMock... but I thought I'd put it out there that I do this successfully with Kiwi and it looks like this.

it(@"should refresh the client's temporary API key if it is stale before sending the request", ^{
    ISLDataServiceAdd *addRequest = [ISLDataServiceAdd withRecord:@{ISLFieldContact_FirstName: @"Jason"} table:ISLTableContact];

    [[clientMock shouldEventually] receive:@selector(apiKey) andReturn:VALID_API_KEY];
    [[clientMock shouldEventually] receive:@selector(hasTemporaryAPIKey) andReturn:theValue(YES)];
    [[clientMock shouldEventually] receive:@selector(isTemporaryAPIKeyStale) andReturn:theValue(YES)];
    [[clientMock shouldEventually] receive:@selector(refreshTemporaryAPIKeyAndWait:)];

    [addRequest sendRequestUsingClient:clientMock completion:nil failure:nil];
});

sendRequestUsingClient:completion:failure: is an asynchronous call, so by using shouldEventually with Kiwi, it knows that it needs to wait some time (default is 1 second) before those selectors will be called.

Chris Wagner
  • 20,773
  • 8
  • 74
  • 95
  • Chris, thank you for your answer. At the moment I'm investigating unit testing for iOS in common and founding this task too big )). I'm not using Kiwi at the moment but probably I'll do it in the feature. At the moment I've found how to solve my problem. I just directly call method I needed without any method replacing or something like that. Anyway thank you a lot for your help, probably your answer will be helpful for me in the future. Or will be helpful for someone else. – Rostyslav Druzhchenko Jun 02 '13 at 13:23