I have an unit test which calls methods on CNContactStore() e.g. CNContactStore().execute(saveRequest). So the permission dialog for contacts pops up, like the Push notifications alert but the contacts permission dialog doesn't get dismissed automatically. I know how to do this in UI tests with addUIInterruptionMonitor() but have no idea how to do this in unit test.
I would create a wrapper around CNContactStore and then use a mock when testing.
You're not really interested in testing CNContactStore, you are interested in testing that your code interacts with CNContactStore properly right?
Setup
I would start out creating protocols and classes to extract the contact stuff out of your "normal" code base.
First a Contact struct to hold the properties you need later to create an actual CNContact
struct Contact {
//holds whichever properties you need to create a CNContact
}
Then a protocol to hold the methods you would like to execute. This could be done with a protocol with a lot of methods like so
protocol ContactsHolder {
func save(contact: Contact)
func add(contact: Contact)
func delete(contact: Contact)
func update(contact: Contact)
//Maybe more methods, the important thing is that you abstract yourself away from CNContactStore and other Contact kit classes
}
Or you could create an enum holding the possible options like so
enum ContactsUpdateMethod {
case save(Contact)
case add(Contact)
case delete(Contact)
case update(Contact)
}
protocol ContactsHolder {
func execute(_ method: ContactsUpdateMethod)
}
In Your "Real" Code
With that in place, you are ready to create your actual ContactsHolder, which then internally uses CNContactStore and everything related to that framework.
So for instance (if you chose the version with a "pure" save function)
class CNContactsHolder: ContactsHolder {
func save(contact: Contact) {
//1. create a `CNContact` from your `Contact`
//2. create a saveRequest
//3. execute: CNContactStore().execute(saveRequest)
}
....
}
And then you give the class(es) who needs to work with CNContactStore a reference to your new ContactsHolder protocol
So in your class you have
let contactsHolder: ContactsHolder
And then you can either pass it in, in your init method
init(contactsHolder: ContactsHolder = CNContactsHolder()) {
self.contactsHolder = contactsHolder
}
Or you can declare it as a var and then give it a default value
So instead of:
let contactsHolder: ContactsHolder
You say:
var contactsHolder: ContactsHolder = CNContactsHolder()
The important thing is that you can change the ContactsHolder from being a "real" CNContactsHolder into a mock when you need to test
In Your Test Code
To test this, you create a mock:
struct MockContactsHolder: ContactsHolder {
var saveWasCalled = false
func save(contact: Contact) {
saveWasCalled = true
}
}
And then you use that in your class instead of the CNContactsHolder
Now you should be able to test your own code, without getting interrupted with permissions and stuff that is not relevant to your code, but is a consequence of using CNContactStore.
Disclaimer :)
I haven't run the above by a compiler, so there may be typos.
Also, there might be bits and pieces missing to make it fit to CNContact (callbacks and so on), but I hope you get the idea about how to split things apart.
And finally...it may seem like a lot of work, but I think it makes sense to get the "framework specific" code out into a separate helper class, hid behind a protocol, so that you can swap it out whenever you need to do testing for instance, or...if you decide to get rid of CNContact at a later point and use a different frameworks.
Hope it helps.
I think you're confusing Unit Testing with UI Testing. In Unit Testing, you just want to test, your codes (e.g. functions and properties) and with that, you'll most probably need to have "mock-up".
For instance, you want to test your login button selector that has a network calls after validation of the input fields.
The following should be the steps:
Test your validation logic. Both failing and succeeding cases.
Test the code inside the completion block of your API call, BUT not using the REAL API data. Instead, use your mocked API here.
and so on...
Now, back to your question, you don't need to handle that uncontrollable and "un-dismissable" alert controller generated by the system. Instead, what you wanna do is to "mock" (ughh not again) that pop-up event by hitting the delegate function for that access-contacts alert by the system, "mock" a response namely "Don't Allow" and "OK". What do you expect to happen when user taps on the first button? The second button? Set expectations/assert.
That's it. Hit every function you need to hit to increase the coverage of your code. Let me know if this helps.
Related
I am trying to unit test a two functions in a view controller class. The two functions will create a user and sign in a user respectively. My tests are not UI related.
As of now, I simply need to create a test that passes when one of the functions is called. The goal is to do this without changing the current view controller implementation if possible and just keep it all in the testing class/function.
How do I go about this?
Thanks
I'm assuming a view controller with a method that invokes either "create user" or "sign in user". (You say it's not UI related, but we can easily test button taps if that's the trigger.)
class MyViewController: UIViewController {
func triggeringMethod() {
// Calls one of the two methods below
}
func createUser() {
// Does stuff
}
func signInUser() {
// Does stuff
}
}
And it sounds like you want to test the flow, but not the effect. That is, you want to test "Was createUser() called?" There are several ways to get what you want, but the better ways will require you to change your view controller implementation.
Making a Partial Mock
A standard trick from Working Effectively With Legacy Code by Michael Feathers is "Subclass and Override Method". Let's start there. In test code, we can make
class TestableMyViewController: MyViewController {
override func createUser() {
}
override func signInUser() {
}
}
So far, this is a way of stubbing out the effects of these methods. But we can now add the mocking techniques from my try! Swift Tokyo talk.
class TestableMyViewController: MyViewController {
var createUserCallCount = 0
var signInUserCallCount = 0
override func createUser() {
createUserCallCount += 1
}
override func signInUser() {
signInUserCallCount += 1
}
}
Now you can call the triggering method, and check the call counts.
(Changes you may have to make: The class can't be final. The methods can't be private.)
Moving the Workers
While this is a fine place to start, don't stop there. What we've created is a "partial mock". That's where we've kept most of the functionality, but mocked out a couple of the methods. This is something to avoid. The reason is that we end up with class that mixes production code and test code. It would be far too easy to end up in a situation where you're inadvertently testing test code instead of testing production code.
What the partial mock makes clear is that we're missing a boundary. The view controller is doing too much. The actual work of "create user" and "sign in user" should be performed by another type (possibly even 2 types). In Swift, we can define this boundary with a protocol. That way production code can use the real functionality, while for test code we can inject mocks.
This means the production code should avoid deciding for itself who does the actual work. Instead, we should tell it who does the work. That way, tests can provide alternative workers. Specifying these dependencies from the outside is called "Dependency Injection".
Passing Back Effects
Another option lets us avoid mocks altogether. Instead of testing whether something was called, we can describe the desired effect in an enumeration. Then we can define effects like
enum Effect {
case createUser(CreateUserRequestModel)
case signInUser(SignInUserRequestModel)
}
Instead of the triggering method calling createUser() or signInUser(), it would call a delegate. (Another option is to pass in closures instead of specifying delegates.)
protocol Delegate {
perform(_ effect: Effect)
}
Then in the triggering method,
delegate?.perform(.createUser(parameters))
This means it's up to the actual delegate to transform these enumeration values into actual work. But it makes the tests easy to write. All we need is to provide a testing implementation that captures the Effect value.
I have this use case where a model object (e.g. class User) has few methods.
Some of the methods in the class require authentication (e.g. getProfile, getFriends,...).
class User{
var loginDelegate:LoginDelegate
func getProfile{
HTTPAsync.getProfile(payload){response in
if response.status == 401 {
login(delegate)
}
}
func getFriends{
//similar code as above
login(delegate)
}
Once, user is successfully logged in, I want to call respective functions (getFriends, getProfile, whichever invoked login).
I have been thinking to use delegate pattern. But since my class (user) has multiple methods that require login, I need to pass some data to delegate, which must be read after user is logged in to call the appropriate method.
I am new to Swift, and was wondering if I am going in the right path. Is there any other obvious way to achieve this pretty common problem.
In my app, use a Url whiteList to solve this problem,
For example, the Url inside the user authentication interface which contains "/users/" this string (or other strings), when the user is not logged in and used a request for such a Url to send out a notification, by a unified class to receive this notification,then Pop up Login box
I am new to Swift, and was wondering if I am going in the right path. Is there any other obvious way to achieve this pretty common problem.
Yes there are a couple of ways you might choose to solve this. e
Define getter methods on your delegate protocol, if it is not your own delegate protocol you can use an extension to extend it's functionality.
Create an Enumeration as an instance variable so you can set an enumeration value with in the login method that your other methods can access after the login method finishes.
Change the login method to accept more parameters and returns a value\object.
For example:
login(delegate: LoginDelegate, dictionaryOfOtherStuff: [String :AnyObject]?) -> (value_1: String, value_2 : [int])
I can only give an example since you have not stated exactly what needs to be available after the login method is called.
I'm new in Swift and even in object oriented programming languages itself. So my question is, how to use this very extensive language Swift the right way? I give an example to verify my problem:
Let's say I have got two classes:
Class ScanForBluetoth{} //Handles all parts to scan for BT devices
class ScanForDevices: UIViewController, CBCentralManagerDelegate , CBPeripheralDelegate, UITableViewDelegate,UITableViewDataSource{}
Class Bluetooth{} //Handles only the Bluetooth parts with it's delegates
class Bluetooth: ScanForDevices{}
Now, I would like to implement all my used delegates and other Bluetooth specific functions into the Bluetooth class. BUT I need some objects (for example of the CBCentralManagerDelegate) in my ScanForDevices class, too. So, I have to implement all my delegates in my "mother" class ScanForDevices although I only need some properties. SO if I implement the delegates, I have to be conform with the protocol and must implement ALL my needed delegate functions... At the end I have implemented all my delegate functions in ScanForDevices and then override them in Bluetooth. But I don't think that my way is the best way to realize this problem...
Thanks for reading!
Firstly, I would like to point out that your naming conventions are really off. In object oriented programming, you want your class names to be objects (nouns). You named your classes by what they were doing, rather than what they are. A better name choice for your classes would be something like BluetoothDeviceScanner, rather than scan for devices, and BluetoothManager rather than the non-explicit "bluetooth".
Secondly, what you have done is subclassed the bluetooth class to scan for devices class, which causes it to inherit all the functionality of its class. This really doesn't make any sense. Subclassing is used to create an object based on a parent object, while these two objects handle two totally different things, and then you're planning on overriding the functions anyway. Instead of that, you should just include the protocols that you need in the bluetooth class separately. Keep the functionality of the two classes separated as much as possible.
Thirdly, you should separate your view controller functionality from the scanning functionality. What I mean is the "ScanForDevices" object's job is to scan for devices, so it shouldn't also have the job of controlling a view... I would remove the UIViewController protocol and introduce a new view controller class, and within that class you can have a property that is assigned the "ScanForDevices" object, at which point the devices can be scanned for within the viewcontroller, but the scanning functionality is contained within a single object (which is best practice).
EDIT
All you need to do to "connect" the data is have your BluetoothManager and BluetoothScanner objects is have them available as a property within whatever view controller you need them. So, in the viewcontroller declare some properties, I usually do it with optionals so that I don't have to worry about initializing the properties (This means you need to unwrap the variables before using them).
In your ViewController...
var bluetoothScanner: BluetoothScanner?
var bluetoothManager: BluetoothManager?
override func viewDidLoad() {
super.viewDidLoad()
bluetoothScanner = BluetoothScanner(init parameters)
bluetoothManager = BluetoothManager(init parameters)
}
You're objects are now "connected" in the sense that you have access to them and all their properties/methods in the viewcontroller. Now that I think about it, you don't even need to have both objects on this level. You can store the BluetoothScanner as a property of the Bluetooth manager, at which point you would only need to use a BluetoothManager object to handle all your bluetooth needs on the view controller level.
Init Methods
//init method that takes 2 parameters, a string and a uiviewcontroller.
init(param1: String, param2: UIViewController) {
//Struct init code using parameters
self.name = param1
self.viewController = param2
}
//init method that takes no parameters, but still initializes the same properties.
init() {
self.name = "YungGun"
self.viewController = UIViewController()
}
Keep in mind these initialization methods are made up and have nothing to do with your problem at hand, I was attempting to illustrate that this is where you define the parameters needed to initialize the struct. The same parameters in the parenthesis must be passed when creating an instance of the struct.
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 ?
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.
https://en.wikipedia.org/wiki/Observer_pattern
It will help you to decouple event publisher (Observable) and consumer (Observer).
Also you can have a special Observable implementation
which doesn't connect to anywhere but notify the observers with static content.
So you directly call notifyObservers method, for testing the behavior of Observers.
I'm a bit sceptic wether this belongs to stackoverflow or not, please let me know if I should post to codereview or programmers instead.
I want to write a reusable component for iOS that does something like this:
Accepts a number as an input, let's call it inputNumber
Records audio for 10 seconds or until the user stops recording
During recording shows live metering
After the recording, checks the recording using the provided inputNumber (we don't really care about this part at the moment)
Allows the user to play the recorded audio
Returns a path to the recorded file
Returns YES or NO based on the check of step 4
The GUI is pretty simple, just two buttons (play/pause and record/stop) together with a view for showing the audio metering during recording.
Something like this:
Now, I have implemented all the logic I need in a singleton "manager" class and what I want to do is also provide the GUI. That means that the consumers will not care about enabling/disabling buttons, showing/hiding the meter etc.
I would like for others to be able to keep using this "manager" (and probably it will be refactored to stop being a singleton), but at the same time I would like to give the option to use it as a "drop in" view.
So, this is a question of how can I setup the whole architecture.
Right now my manager has only one method:
typedef void(^CompletionBlock)(BOOL isValid, NSString* filePath, NSError *error);
-(void)evaluateRecordingForInputNumber:(NSNumber *)inputNumber completion:(CompletionBlock)completionBlock;
and this works as I want.
But if I introduce a view, how should my API look? It doesn't seem correct to me to write a custom UIView -init that will take the role of the aforementioned method, since ideally I would like to reuse this view for different model classes (providing the inputNumber) that need to be evaluated.
How can I choose between subclassing NSObject, UIControl or UIView in my case? Is there a nice way to use both my "engine" as a standalone component and also optionally provide a backing view layer?
I think this coupling is largely dependent on how you envision the custom view/manager being used.
Will it be a lot of logic that people can use without the view, and the view is just an optional feature? If so it likely makes sense to subclass NSObject and prove the view as a property of the manager itself. That way people can use your manager class as a standalone, and in UIView's where it's needed they can do something like the following:
[self.view addSubview:myCustomManager.audioView];
On the other hand if the manager class has no value to your user without the UIView itself then I think it makes a lot of sense to subclass UIView, and hide your manager class behind that UIView. One example of a widget that uses this style of implementation is stripe: Stripe iOS Widget. Everything is based off of their 'STPView', like retrieving a charge token:
[self.stripeView createToken:^(STPToken *token, NSError *error) {
if (error) {
// Handle error
// [self handleError:error];
} else {
// Send off token to your server
// [self handleToken:token];
}
}];}
One can imagine a private 'manager' class behind the scenes of the stripeView doing all the work (this method is in addition to their delegate callback).
In your case this might be a fairly good pattern. You can add a property to the custom view for the number to be evaluated, add the view to the hierarchy, and then create a custom delegate that calls back automatically after it processes things; which would take the place of your manager class callback.
The final answer is that it depends a lot on how much of split between business logic and UIView treats this will provide. As long as the code is readable, maintainable, and you have some reasonable pattern to follow I don't think anyone is going to nail you to a cross in iOS land.