【发布时间】:2014-10-10 06:52:39
【问题描述】:
在 Swift Xcode6-Beta5 中,我正在尝试对我的“ViewController”进行单元测试,这不是一个很有创意的名称。
通过查看其他回复,我认为我的“测试”目标配置不正确。
失败的测试代码:
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")
}
我可以用以下几行强制转换:
anyVC = storyBoard?.instantiateInitialViewController()
viewController = (anyVC != nil) ? (anyVC as ViewController) : nil
但这导致了以下崩溃:
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)
我还成功地直接实例化了 ViewController,但这并没有进行 IBOutlet 处理,这是我测试的目的之一,以确保我不会通过重命名、删除连接中的连接来破坏链接故事板编辑器,或者我发现的许多其他破坏方式......
编辑---- 我从一个新项目开始,选择了 iOS 应用程序 -> 单视图应用程序模板。
将 testExample 替换为如下所示的代码,将 ViewController 添加到测试目标中。类似的结果。这个模板有一个 ViewController 类型的视图控制器,故事板中没有其他内容。
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")
}
在 anyVC 的值设置后的断点处的以下 lldb 输出:
(lldb) po anyVC
(instance_type = Builtin.RawPointer = 0x00007fe22c92a290 -> 0x000000010e20bd80 (void *)0x000000010e20bea0: OBJC_METACLASS_$__TtC22TestingViewControllers14ViewController)
{
instance_type = 0x00007fe22c92a290 -> 0x000000010e20bd80 (void *)0x000000010e20bea0: OBJC_METACLASS_$__TtC22TestingViewControllers14ViewController
}
【问题讨论】:
-
看起来
anyVC不是ViewController类型,那么您确定故事板中的初始视图控制器实际上是该类型吗?确保 (1) 在身份检查器中检查初始视图控制器的类并 (2) 在instantiateInitialViewController()之后设置断点并查看anyVC的类型。使用您找到的信息编辑您的问题。 -
我可能会抢先一步:rdar://18043164
-
在我看来,问题在于storyboard中ViewController的类型是App.ViewController,与ViewController不同。请记住,swift 有模块。当您将 ViewController 链接到您的测试目标时,您有效地创建了该类的两个版本:App.ViewController 和 AppTests.ViewController,它们并不相同(它们不会正确转换)。我不知道如何从测试目标中的应用目标引用 Swift 类。不过,一定有办法。希望对您有所帮助。
-
在
instantiateInitialViewController调用之后添加println(anyVC)、println(ViewController())说明了区别。 -
@DerrickHathaway 感谢您指出这一点。我也有这个问题。我看到当我使用您的
println()语句时,我得到了 Target.ViewController 这可能是问题的根源。