How can I verify method calls to an NSURLProtocol mock using OCMock or OCMockito? - objective-c

I would like to test a method which makes a GET request.
Here's a contrived example:
- (void)GET:(NSString *)URLString;
Rather than worry about the implementation details of this method (e.g. mocking, setting expectations, and then verifying a dependency), I'd prefer to just be able to test if the GET request was made.
I believe I can do this with NSURLProtocol but my attempts so far have been unsuccessful.
For example, using OCMock:
id mockURLProtocol = (NSURLProtocol *)[OCMockObject mockForClass:[NSURLProtocol class]];
[NSURLProtocol registerClass:mockURLProtocol];
[[mockURLProtocol expect] canInitWithRequest:[OCMArg any]];
[MYClass GET:#"test"];
[mockURLProtocol verify];
[mockURLProtocol stopMocking];
[NSURLProtocol unregisterClass:mockURLProtocol];
The above test fails since canInitWithRequest is never called.
How can I set expectations on NSURLProtocol to verify that the request is being made?

Mocking NSURLProtocol doesn't make sense to me. NSURLProtocol is used in testing to create canned responses to certain requests, there is no need of mocking it (you don't want to test how the system interacts with it). This project makes use of NSURLProtocol, it may be useful for you in case you want to use this approach instead of a pure unit test where you test your NSURLConnectionDelegate implementation directly.

Related

Using OCMock to mock an internal object and change the behavior of a instance selector

I'm trying to use OCMock to modify the behavior of an instance selector for a specific class where I don't have a direct pointer to the instance of the class in question.
I've found a few posts online that claim to allow doing at least part of this, for example: How to mock an object with OCMock which isn't passed as a parameter to method?
I tried following the guidance in one of the answers in that post, specifically relying on code like this:
id mockController = OCMClassMock([WebAuthViewController class]);
OCMStub([mockController alloc]).andReturn(mockController);
OCMStub([mockController initWithAuthenticationToken:OCMOCK_ANY authConfig:OCMOCK_ANY]).andReturn(mockController);
However, I am having difficulty understanding this code. First of all, where does the actual "alloc" logic run? The code seems to be saying "mock alloc and return an existing class method", but alloc is supposed to return an instance, not a class. Is this some magic build into OCMock?
Also, on a related matter it seems the init is simply returning the same mocked class, not an instance of that class. It seems really strange that this returns the same thing as the previous mock, and I don't understand where the actual custom init logic is being called. It seems to be omitted completely since there is no call to .andForwardToRealObject() anywhere.
However, ultimately my main problem is I don't understand how to mock an instance method using the above code since things are working on class, not an instance. I tried to write a similar mock to modify the behavior of an instance method (using the equivalent of mockController above), but it said the method was not there.
I tried a bunch of things, but could not get OCMock to handle this case. If anyone can point me to an example that mocks a specific instance method for all instances of a class, I'd appreciate it.
By the way, I was able to get things working by using swizzling without any use of OCMock, but it seems really hacky (especially when I'm using OCMock for everything else), so I would love to get this working with OCMock.

How to write an Objective-C REST API wrapper

I’m working of writing an Objective-C wrapper for a REST API. A lot of what I’m reading says not to use synchronous NSUrlConnection requests to avoid blocking the main thread. This makes sense, but I am wondering, what is the best way to make an API wrapper in Objective-C?
For example, we have an API method that takes a session ID and returns whether or not the session is valid. Ideally the wrapper method prototype would look like the following:
- (BOOL) sessionIsValid:(NSString *)sessionId;
So, that method could be called and the return value could be used to decide what to do next. But how would this work if the API call is asynchronous? It seems like the caller would need to set itself as the wrapper's delegate, make a request, and then process the response from the delegate method. Seems pretty ugly for such a simple API call. Is there a good way to achieve this?
Whether a session is valid or expired, should be an implementation detail of the underlying network layer. Thus, you would rarely have this method in a Objective-C API. Rather you would have an API that looks more like this:
typedef void (^completion_t)(id result, NSError* error);
- (void) fetchAllPostsWithUser:(ID)userID completion:(completion_t)completionHandler;
This is an asynchronous method. The call-site will be notified about the completion through calling the completion handler, which passes the result of the operation and possibly an error object. What result is actually, is entirely up to you: it may be an NSArray of custom objects of class Post or it may be JSON (either serialized or as objects), or whatever. In any case it must be clearly defined in the documentation.
Your "session problem" is part of the authentication scheme. In many cases, NSURLSession, respectively NSURLConnection can already handle authentication completely transparent for you. If not, there are a few delegate methods which can be overridden where you can tailor the behavior. A client (a developer using this API as a library) of that Objective-C API should never be concerned with such "abstract" and "obscure" notions like "session". He/she, knows just passwords, users, posts, etc. ;)
If you wanted to return a BOOL you would need to have already setup the session and cached the validity (expiry date) - which isn't always going to be possible. A delegate pattern is a good option. Don't forget that you can implement the delegate pattern using blocks (which give you the option of having multiple different delegates all using the API at the same time).

Unit testing NSURLConnection sendAsynchronousRequest with OCMockito

I'm struggling to write a unit test for an API wrapper with an interface like
- (void)publish:(id<MyCustomRequest>)aRequest completionHandler:(void (^)(id<MyCustomResponse>, NSError *)) completionBlock
which calls this method under the hood:
NSURLConnection sendAsynchronousRequest:queue:completionHandler
I don't want to use a delegate instead, as the exposed API fits much more comfortably with the sendAsynchronousRequest method (and doesn't require a separate accumulator object per-request). Further, I am using OCMockito for mocking throughout the rest of the code, which doesn't support partial mocks or mocking class methods.
Are there any other testing techniques that my be able to test this function? Is it necessary to use a delegate instead?
Use the delegate-based API. I realize it's more code, but the convenience API is clearly not adequate to meet your needs (i.e. mockable with OCMockito). Furthermore, don't worry about the "overhead" of allocating one ancillary per request. I feel quite confident that there will be dozens of objects allocated behind the scenes in the system frameworks by virtue of your calling +[NSURLConnection sendAsynchronousRequest:queue:completionHandler:]; you shouldn't be concerned. That said, a single object can be the delegate for more than one request, so you needn't necessarily have more than one.

Using partialMockForObject to do singleton class mock, how to create a method like "removeAllExpectations” to remove all remembered ones?

Confused on OCMock for singleton, get two methods, but none of them is perfect in my opinion.
Using partialMockForObject.
I want to use partialMockForObject to do singleton class mock. See following code, it works well, but the defect is that singleton [NSNotificationCenter defaultCenter] will remember previous mock behavior, then when invoked in another place, it will crash, unexpected. So my question is that how can I create a method like "removeAllExpectations” to remove all remembered ones?
id aMock = [OCMockObject partialMockForObject:[NSNotificationCenter defaultCenter]];
[aMock expect] removeObserver:[OCMConstraint isKindOfClass:[WhereIsMyPhoneViewController class]]];
[[aMock verify];
Using category method. See http://twobitlabs.com/2011/02/mocking-singletons-with-ocmock/ mentions another method to do singleton mock, personally I prefer partialMockForObject, you don't need to mock all methods when unit testing.
Have sent my question to OCMock development group but no response got yet, need your smart guys opinion. Any idea or discussion will be appreciated, thanks in advance.
If you are using the lastest source code of OCMock (after
2012-04-06), call
[aMock stopMocking];
to reset the mocked object's state.
You can call:
[aMock stop];
to reset the mocked object's state.

Unit testing with NSURLConnection

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.
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.
I modified OCMock to support real partial mocks, see the repo on GitHub.
Another solution I have used recently is to completely abstract the networking interface. If the class needs some data from the network, it probably interacts with some server service that can be explictly modelled as a protocol:
#protocol SomeNetworkService
- (NSArray*) allAvailableFoos;
- (void) insertNewFoo: (Foo*) foo;
#end
And then you’ll have a real HTTP implementation and a testing one. This means more work, but also much better testability. The tests are less brittle and much more convenient, since the testing network layer can do whatever you need.