In Swift, Xcode6-Beta5, I'm trying to unit test my "ViewController", not a very creative name.
From looking at other responses, I'm thinking I don't have my "Tests" target configured properly.
Failing test code:
func testItShouldLoadFromStoryboard() {
var storyBoard: UIStoryboard?
var anyVC: AnyObject?
var viewController: ViewController?
var uiViewController: UIViewController?
storyBoard = UIStoryboard(name:"Main", bundle: nil)
XCTAssert(storyBoard != nil, "Test Not Configured Properly")
anyVC = storyBoard?.instantiateInitialViewController()
viewController = anyVC as? ViewController
// Failing Assertion
XCTAssert(viewController != nil, "Test Not Configured Properly")
uiViewController = anyVC as? UIViewController
XCTAssert(uiViewController != nil, "Test Not Configured Properly")
}
I can force the cast with the following lines:
anyVC = storyBoard?.instantiateInitialViewController()
viewController = (anyVC != nil) ? (anyVC as ViewController) : nil
But this caused the following crash:
libswiftCore.dylib`swift_dynamicCastClassUnconditional:
0x10724f5a0: pushq %rbp
0x10724f5a1: movq %rsp, %rbp
0x10724f5a4: pushq %r14
0x10724f5a6: pushq %rbx
0x10724f5a7: movq %rsi, %rbx
0x10724f5aa: movq %rdi, %r14
0x10724f5ad: testq %r14, %r14
0x10724f5b0: je 0x10724f5de ; swift_dynamicCastClassUnconditional + 62
0x10724f5b2: movabsq $-0x7fffffffffffffff, %rax
0x10724f5bc: andq %r14, %rax
0x10724f5bf: jne 0x10724f5de ; swift_dynamicCastClassUnconditional + 62
0x10724f5c1: movq %r14, %rdi
0x10724f5c4: callq 0x107279a6e ; symbol stub for: object_getClass
0x10724f5c9: nopl (%rax)
0x10724f5d0: cmpq %rbx, %rax
0x10724f5d3: je 0x10724f5ed ; swift_dynamicCastClassUnconditional + 77
0x10724f5d5: movq 0x8(%rax), %rax
0x10724f5d9: testq %rax, %rax
0x10724f5dc: jne 0x10724f5d0 ; swift_dynamicCastClassUnconditional + 48
0x10724f5de: leaq 0x3364d(%rip), %rax ; "Swift dynamic cast failed"
0x10724f5e5: movq %rax, 0xa456c(%rip) ; gCRAnnotations + 8
0x10724f5ec: int3
0x10724f5ed: movq %r14, %rax
0x10724f5f0: popq %rbx
0x10724f5f1: popq %r14
0x10724f5f3: popq %rbp
0x10724f5f4: retq
0x10724f5f5: nopw %cs:(%rax,%rax)
I've also successfully instantiated the ViewController directly but that doesn't do the IBOutlet processing, which is one of the purposes of my tests, to make sure I don't break the linking by renaming things, deleting connections in the Storyboard editor, or the many other ways I have found to break things ...
EDIT ---- I started with a fresh project, chose iOS Application -> Single View Application template.
Replaced the testExample with the code as shown below, Added ViewController to the test target. Similar results. This template has a single view controller of type ViewController, nothing else in the storyboard.
func testExample() {
var storyBoard: UIStoryboard?
var anyVC: AnyObject?
var viewController: ViewController?
storyBoard = UIStoryboard(name:"Main", bundle: nil)
XCTAssert(storyBoard != nil, "Test Not Configured Properly")
anyVC = storyBoard?.instantiateInitialViewController()
viewController = anyVC as? ViewController
XCTAssert(viewController != nil, "Test Not Configured Properly")
// This is an example of a functional test case.
XCTAssert(true, "Pass")
}
The following lldb output at a break point just after the value of anyVC is set:
(lldb) po anyVC
(instance_type = Builtin.RawPointer = 0x00007fe22c92a290 -> 0x000000010e20bd80 (void *)0x000000010e20bea0: OBJC_METACLASS_$__TtC22TestingViewControllers14ViewController)
{
instance_type = 0x00007fe22c92a290 -> 0x000000010e20bd80 (void *)0x000000010e20bea0: OBJC_METACLASS_$__TtC22TestingViewControllers14ViewController
}
I came up with a better solution than making everything public. You actually just need to use a storyboard that comes from the test bundle instead of using nil (forcing it to come from the main target's bundle).
var storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: NSBundle(forClass: self.dynamicType))
vc = storyboard.instantiateViewControllerWithIdentifier("LoginVC") as LoginViewController
vc.loadView()