Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two classes, callback and unit testing

I have one class with static methods : this class wraps calls to the Twitter API

In a second class, I have some business logic.

Due to the asynchronousness behaviour of some methods in the wrapper class, I have difficulties to design the communication. Here is what I've done :

APIManager.swift

public class APIManager {
    class func getPermission(callback : () -> Void) {

        let accountStore = ACAccountStore()
        let accountType = 
        ACAccountStore().accountTypeWithAccountTypeIdentifier(ACAccountTypeIdentifierTwitter)

        let callbackRequestAccess = { (granted: Bool, error: NSError!) -> Void in
            ...
            if(granted) {
                callback()
            }

        }

        accountStore.requestAccessToAccountsWithType(setAccountType, 
                     options: nil, completion: callbackRequestAccess)

    }
}

Welcome.swift

public class Welcome {

    public func checkPermission() {
        APIManager.getPermission(getTweet)
    } 
    public func getTweet() {
        ...
    }        
}

I am not sure that this design in right or not. I don't want to have a strong link between those classes, that's why I am using a callback.

Is this a classic design ? Moreover, I don't feel like this behaviour will be easy to test ?

like image 391
Max Avatar asked Aug 07 '15 19:08

Max


1 Answers

You will greatly improve testability by not using class methods here. Create a TwitterConnection protocol. Create a SystemTwitterConnection that conforms to it and manages things through ACAccountStore. Create a TestTwitterConnection that returns pre-set responses that you can configure for testing. You could even create a KeychainTwitterConnection to manage Twitter logins by hand without using ACAccountStore, or some other implementation if Apple comes out with yet another way to store these accounts.

Pass the appropriate connection to Welcome when it is created.

If the TwitterConnection protocol gets large, you should strongly consider splitting it up into smaller protocols, such as TwitterAuthenticator and TweetFetcher that handle fewer things (even if a single type actually implements all of those protocols). This can make testing much easier by allowing your test types to implement just a few functions rather than dozens.

The use of closures is probably fine, but you should stick more closely to Cocoa naming conventions. What you're calling a callback is traditionally called completion. I'd also follow Cocoa's lead on how to name methods. Rather than getPermission(), it would be requestAccessWithCompletionHandler(). This would help the caller understand that it has very similar behavior to requestAccessToAccountsWithType(options:completion:). Don't built a new vocabulary for the caller.

like image 53
Rob Napier Avatar answered Sep 17 '22 20:09

Rob Napier