Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot access AppDelegate in XCTestCase objects (or anything that references it)

I am trying to start unit testing on my swift iOS app but have run in to a total road block. I cannot seem to access anything that uses my appDelegate.

My appDelegate has a UserController object which stores and manages the logged on user and it's various pieces of data. In order to simplify calling the userController I created a custom subclass of NSObject which all my model classes subclass. In it it has

let userController : UserController = (UIApplication.sharedApplication().delegate as! AppDelegate).userController

This line causes a SIGABRT exception whenever i try and test one of the subclassing models.

Could not cast value of type 'MyProject.AppDelegate' to 'MyProjectionTests.AppDelegate'.

I have tried removing AppDelegate from the test target, but this then gives me AppDelegate is undefined. I have tried adding import MyProject into the top of the test file, but that didn't work either.

I have seen two other solutions:

  • Make the app delegate functions private - I am really loathed to do something like this. What is the point of testing if I am having to change my code specifically for testing.

  • Implement a testing app delegate and use that - again whats the point in testing if I'm not testing whats in the project.

Does anyone have a solution. Unit testing in Swift is proving to be a total headache after how easy RSpec is with rails

like image 362
AndyRyan Avatar asked Mar 15 '23 02:03

AndyRyan


1 Answers

You can't add AppDelegate.swift to the test target. That causes the class to be created also at test target namespace and it will be a duplicate.

When the AppDelegate object is unwrapped on the test target if fails because the object belongs to the version of the class AppDelegate defined on the main target, but is the code is trying to unwrap the object as if it belongs to the version defined on the test target.

What it is needed is to enable the main target has a module so all of his classes can be imported into the test code, like any kit.

To define main target as module do this: enter image description here

Then import the module and access the object do like this:

import UIKit
import XCTest
import MyApp


class MyAppTests: XCTestCase {

    func testExample() {
      let userController : UserController = (UIApplication.sharedApplication().delegate as!  AppDelegate).userController
    //or explicitly referencing the module
let userController : MyApp.UserController = (UIApplication.sharedApplication().delegate as!  AppDelegate).userController 
    }
}

}

Class AppDelegate and property userController has to be made public. If you already are using Swift 2.0 you can use testable attribute instead of changing the isolation level. Check this tutorial to see how.

like image 135
MiguelSlv Avatar answered Mar 17 '23 15:03

MiguelSlv