7

I'm trying to use unit test in swift to test some of the real application behaviour. When i try to cast de UIApplicationDelegate to my AppDelegate from my test function i got and EXC_BAD_ACCESS exception. Below the test code:

func testGetAppDelegate(){

    let someDelegate = UIApplication.sharedApplication().delegate
    let appDelegate =  someDelegate as AppDelegate //EXC_BAD_ACCESS here
    XCTAssertNotNil(appDelegate, "failed to get cast pointer")
}

AppDelegate class is set to public so it is not a problem from access level.

Using objective-c in the same test target it works. Below the simple instruction:

AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

The debuger says someDelegate is a Builtin.RawPointer. Don't know what that is, i am not familiar with low level details.

MiguelSlv
  • 14,067
  • 15
  • 102
  • 169

3 Answers3

10

I think you added AppDelegate.swift to the tests target members.

When you do that, AppName.AppDelegate and AppNameTests.AppDelegate becomes different classes. Then, UIApplication.sharedApplication().delegate returns AppName.AppDelegate instance, but you are trying to cast it to AppNameTests.AppDelegate type. That causes EXC_BAD_ACCESS.

Instead of that, you have to import it from your application module.

import UIKit
import XCTest
import AppName // <- HERE

class AppNameTests: XCTestCase {
   // tests, tests...
}

And, AppDelegate class and its methods and properties must be declared as public to be visible from test module.

import UIKit

@UIApplicationMain
public class AppDelegate: UIResponder, UIApplicationDelegate {

    public var window: UIWindow?

    public func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }

    // ...

Again, Be sure to remove AppDelegate.swift from the Test target members.

rintaro
  • 51,423
  • 14
  • 131
  • 139
  • You guessed right, many thanks. Still have to digest this information to find out what is the right approach for testing, some posts suggest to do as i was doing, but the way i was doing was the problem. – MiguelSlv Nov 15 '14 at 16:09
  • 1
    Some independent classes, such like `DateUtility`, can be directly add to tests target. But the classes tied to the main application, such as `AppDelegate` or CoreData related, cannot be testable without importing them from the main application module. So to say, for the "unit tests", direct adding is OK. But for the "application tests", import them. – rintaro Nov 15 '14 at 16:19
  • I am trying to implement what you said here but I am still having issues. My code is located at: http://stackoverflow.com/questions/28042105/swift-dynamic-cast-failed-swift-dynamiccastclassunconditional – Nate Uni Jan 21 '15 at 07:39
  • I tried the same for my issue.But it didnt work.any suggestion? – Madhumitha Jun 28 '16 at 06:59
2

With the Swift 2.0 update, keep using rintaro's solution. But you can simplify it by:

@testable import MyApp

Then you don't need to mark your AppDelegate class as public.

Dan M.
  • 51
  • 4
0

Make certain that your AppDelegate has "UIApplicationDelegate" in it's declaration. That is:

@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate {

And if you're doing this for iOS, you might need to import UIKit at the top of this file.

Community
  • 1
  • 1
Michael Dautermann
  • 88,797
  • 17
  • 166
  • 215