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.
Related
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).
While recently working with Objective-C and various libraries written in it, I've noticed two really popular singleton patterns. One version fetches the singleton instance and calls its instance methods and other version only exposes class methods and never gives you an instance to work with. All have the purpose of abstracting access to a single resource (StoreKit, CoreData, Parse API etc.). For example, here's the former approach used in MKStoreKit:
// initialize singleton during app boot
[MKStoreManager sharedManager]
// sometime later in the app
[[MKStoreManager sharedManager] buyFeature:kFeatureAId
onComplete:^(NSString* purchasedFeature)
{
NSLog(#"Purchased: %#", purchasedFeature);
}
onCancelled:^
{
NSLog(#"User Cancelled Transaction");
}];
or alternatively NSUserDefaults, UIApplication etc.. The other approach can be seen in MagicalRecord or here with Parse API:
// configure API credentials sometime during app boot
[Parse setApplicationId:#"123456"
clientKey:#"123456"];
// sometime later
PFObject *testObject = [PFObject objectWithClassName:#"TestObject"];
[testObject setObject:#"bar" forKey:#"foo"];
[testObject save];
What are some pros and cons of the two approaches and is one of them fundamentally better than the other?
Not having to retrieve the shared instance saves some screen estate (the performance difference is likely irrelevant), but am I screwing myself in some other way, for example, testability-wise?
Thanks!
There are two different ways to implement the approach based on class methods:
Make a singleton instance using a class hidden from everybody, and hide its methods behind wrapper class methods with identical signatures, or
Make class methods that do all the work
The implications of the first implementation are that everything you can do with a singleton, you can do with the hidden singleton:
using a subclass becomes a possibility
switching the instance in the middle of the run is easy
the state lives in instance variables
initialization follows the familiar pattern
If you go for an implementation that does not use a singleton, you would be relying on static variables to keep your current state. That is a legitimate choice, but the initialization pattern becomes different (perhaps even using a dispatch_once), you cannot switch the implementation in the middle without relying on some ugly if conditions, and using a subclass becomes a lot more tricky.
Testing the first implementation is somewhat easier than testing the second one, because you can provide a separate implementation of the singleton for testing, perhaps through the back door; with a static-based implementation, this route cannot be taken.
To summarize, I would use a singleton-based solution, with the singleton optionally hidden behind a "facade" that provides access to singleton's methods. I would not use an implementation where all state must be placed in static variables.
One advantage of the singleton approach is that it becomes trivial to allow other instances if you need to. If you take the class method approach, that's all you get without a lot of refactoring.
I have been working with a few applications that deal with NSURLConnections. While researching best practices I have noticed a lot of examples online showing how to use NSOperation and NSOperationQueue to deal with this.
I have also noticed on stackoverflow a few examples that show initializing the connection as synchronous and asynchronous using the class methods of NSURLConnection: sendAsynchronousRequest and sendSynchronousRequest.
Currently I am doing my initialization as follows:
[[NSURLConnection alloc] initWithRequest:request delegate:self];
While doing this I have monitored the main thread and the calls to the delegate methods:
connectionDidFinishLoading, connectionDidReceiveResponse, connectionDidReceiveData and connectionDidFailWithError
Everything I have read in Apples documentation and my tests prove to me that this is asynchronous by default behavior.
I would like to know from more experienced Objective C programmers when the other options would be used for either a best practice, or just be more correct than what I see as the most simplistic way to get async behavior?
This is my first question I have posted on here, if more information is needed please ask.
Synchronous is bad bad bad. Try to avoid it. That will block up your main thread if the data transfer is large, thus resulting in an unresponsive UI.
Yes, it is possible to dispatch a synchronous call onto a different thread, but then you have to access any UI elements back on the main thread and it is a mess.
Normally I just use the delegate methods you have described - it is straightforward, and NSURLConnection already handles the asynchronous call for you away from the main thread. All you need to do is implement the simple delegate methods! It's a little more code, but you always want to go asynchronous. Always. And when it is finished loading, use the information you get to update the UI from the finishedLoading delegate method.
You also have the option of using blocks now, but I can't speak for how well those work or even how to use them well. I'm sure there's a tutorial somewhere - the delegate methods are just so easy to implement.
The method you list are the traditional means of asynchronous transfer and an app that uses them will be efficient in processor (and hence power) use.
The sendAsynchronousRequest method is a relatively new addition, arriving in iOS 5. In terms of best practice there's little other than style to differentiate between it and the data delegate methods other than that a request created with the latter can be cancelled and a request created with the former can't. However the tidiness and hence the readability and greater improbability of bugs of the block-based sendAsynchronousRequest arguably give it an edge if you know you're not going to want to cancel your connections.
As a matter of best practice, sendSynchronousRequest should always be avoided. If you use it on the main thread then you'll block the user interface. If you use it on any other thread or queue that you've created for a more general purpose then you'll block that. If you create a special queue or thread for it, or post it to an NSOperationQueue then you'll get no real advantages over a normal asynchronous post and your app will be less power efficient per Apple's standard WWDC comments.
References to sendSynchronousRequest are probably remnants of pre-iOS 5 patterns. Anywhere you see a sendSynchronousRequest, a sendAsynchronousRequest could be implemented just as easily and so as to perform more efficiently. I'd guess it was included originally because sometimes you're adapting code that needs to flow in a straight line and because there were no blocks and hence no 'essentially a straight line' way to implement an asynchronous call. I really can't think of any good reason to use it now.
In Objective-C, when I want to call a subroutine, I send a message to an object, like:
[self mySubroutine:myParameter];
There is a (negligible?) performance penalty, so I could just use a C-style function call:
mySubroutine(myParameter);
The implementation of the latter would then reside outside the class’s #implementation context.
Is this a no-no? Is it common? Is there a best-practice on this?
Note that those are not necessarily equivalent. Since -mySubroutine is an instance method, it probably needs to access a given instance. In that case, your mySubroutine() function should have another parameter for the instance, too.
In general, use a method. If you’re worried about performance,1 you can always get an IMP to the method and use it as a function instead of the standard Objective-C message dispatch infrastructure.
That said, some disadvantages of using functions:
They cannot be overridden by subclasses;
There’s no introspection (when using the runtime to obtain a list of methods declared by an Objective-C class, functions aren’t enumerated);
They cannot be used as accessors/mutators of declared properties;
They aren’t visible to Key-Value Coding;
They cannot be directly used for Objective-C message forwarding;
They cannot be directly used in the various cases where a Cocoa API expects a selector (e.g. when using NSTimer).
Some advantages of using functions:
They cannot be overridden by subclasses (if you want to prevent this);
There’s no introspection (if you want to prevent this);
They can be inlined;
They can have file scope (static), preventing code from other files from accessing them.
1When you’ve determined that the message dispatch infrastructure is actually a bottleneck. This does happen; for instance, some Apple audio examples do not use Objective-C for audio processing.
Edit: Based on OP’s comment, another advantage of functions is that they aren’t necessarily related to a class. If the computation of an approximate value for the sine of an angle doesn’t depend on an Objective-C instance, there’s no need to make it a method — a function is a better fit.
It might be worth using where you have static utility functions, such as in a maths library.
In general though, if you need methods that act on the state of an object, the C approach won't be much use, as you won't have implicit access to self, unless you explicitly pass it as a parameter.
You may also run into namespace issues. With the Objective-C different classes can share method names, with the c approach all your functions will need different signatures.
Personally I would always use objective-c methods, the performance difference will be negligible.
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.