在XCTest测试中从故事板加载的视图控制器中清空UIView快照(间歇性)

时间:2014-10-02 08:06:23

标签: xcode uiview uistoryboard

我们在项目中跟踪an issue我们会间歇性地失败快照测试用例。我们的方法的要点是渲染视图控制器的视图,并将该图像与参考图像进行比较,以查看它们是否不同。我们的方法有几个层次:

我们的问题是,有时渲染视图创建的图像为空。只是一个大的(正确大小)透明图像。

我已经孤立地对每一个进行了测试,并确定这些都不是问题所在。相反,我已经能够在独立的普通 Xcode项目中重现这一点。

通过使用FBSnapshotTestCases用于呈现视图的same approach,我创建了一个简单的测试。要重现,请创建一个" Master-Detail"的新项目。模板并为详细视图控制器提供故事板ID"详细信息"。然后创建这个简单的单元测试。

func testExample1() {
    let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
    let sut = storyboard.instantiateViewControllerWithIdentifier("Detail") as UIViewController

    sut.beginAppearanceTransition(true, animated: false)
    sut.endAppearanceTransition()

    UIGraphicsBeginImageContextWithOptions(sut.view.frame.size, false, 0)
    sut.view.drawViewHierarchyInRect(sut.view.bounds, afterScreenUpdates: true)
    let image = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()

    let data = UIImagePNGRepresentation(image)

    println("byte length: \(data.length)")
}

没什么太花哨的,而且很可能会过去。但是,如果您再复制代码几次:

func testExample1() { ... }
func testExample2() { ... }
func testExample3() { ... }

输出很奇怪(截断):

Test Suite 'All tests' started at 2014-10-02 07:46:52 +0000
byte length: 27760
byte length: 17645
byte length: 27760
Test Suite 'All tests' passed at 2014-10-02 07:55:29 +0000.
     Executed 3 tests, with 0 failures (0 unexpected) in 517.778 (517.781) seconds

字节长度应该相同,但它们不相同。第二个测试(有时是第三个测试)将有一个空视图,就像我们的问题一样。

Empty image in quick look

展示问题的示例项目here

我能够使用Objective-C测试项目重现该问题,因此它不太可能是Swift问题。在过去的项目中,我们还没有将Storyboard用于我们的视图控制器用户界面,因此可能需要额外的步骤以便强制使用#34;要加载的视图。它也可能是Xcode 6.x或iOS 8问题(我已经用Xcode 6.0.1重现了这个问题)。

有没有人遇到这样的问题,从故事板加载的控制器的视图渲染图像是否透明?

3 个答案:

答案 0 :(得分:2)

好像有把戏......

    let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
    let sut = storyboard.instantiateViewControllerWithIdentifier("Detail") as UIViewController

    sut.beginAppearanceTransition(true, animated: false)
    sut.endAppearanceTransition()

    UIGraphicsBeginImageContextWithOptions(sut.view.frame.size, false, 0)
    let context = UIGraphicsGetCurrentContext
    sut.view.layer.renderInContext(context())
    let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    let data = UIImagePNGRepresentation(image)
    println("byte length: \(data.length)")

答案 1 :(得分:1)

通过切换到生成的UIView来将故事板排除在等式之外:

let view = UIView(frame: CGRectMake(0, 0, 300, 300))
view.backgroundColor = UIColor.blueColor()

UIGraphicsBeginImageContextWithOptions(view.frame.size, false, 0)
view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()

let data = UIImagePNGRepresentation(image)

println("byte length: \(data.length)")

给出类似的结果。

Test Case '-[TestTestTests.TestTestTests testExample1]' started.
byte length: 9663
Test Case '-[TestTestTests.TestTestTests testExample1]' passed (1.000 seconds).
Test Case '-[TestTestTests.TestTestTests testExample2]' started.
byte length: 9663
Test Case '-[TestTestTests.TestTestTests testExample2]' passed (0.112 seconds).
Test Case '-[TestTestTests.TestTestTests testExample3]' started.
byte length: 6469

答案 2 :(得分:0)

正如本主题建议您尝试使用" [self.view.layer renderInContext:UIGraphicsGetCurrentContext()]"代替:

drawViewHierarchyInRect:afterScreenUpdates: delays other animations