UIView.animateWithDuration:animations:completion: 在 XCTest 中被取消

Posted

技术标签:

【中文标题】UIView.animateWithDuration:animations:completion: 在 XCTest 中被取消【英文标题】:UIView.animateWithDuration:animations:completion: gets canceled in XCTest 【发布时间】:2019-05-20 08:59:57 【问题描述】:

我正在尝试对 UIView 上的扩展程序进行单元测试,该扩展程序调用 animateWithDuration:animations:completion:

不幸的是,测试用例中的所有动画都会立即取消,因此完成块的isFinished 参数始终是false

有人知道如何让动画在测试用例中工作吗?

这是我的游乐场代码:

import UIKit
import XCTest

extension UIView 
    func fadeOut(duration: TimeInterval, completion: ((Bool) -> Void)?) 
        UIView.animate(withDuration: duration,
                       animations: 
                            self.alpha = 0.0
                       ,
                       completion:  isFinished in
                            self.isHidden = isFinished

                            completion?(isFinished)
                       )
    


class UIViewTests: XCTestCase 

    func testFadeView() 
        // Given
        let expectation = self.expectation(description: "Expect completion handler to be called.")

        let view = UIView()
        view.alpha = 1.0

        // When
        print("Date before", Date())
        view.fadeOut(duration: 1.0)  (isFinished) in
            print("Date completed", Date())
            print("isFinished", isFinished)

            expectation.fulfill()
        

        // Then
        wait(for: [expectation], timeout: 1.1)

        XCTAssertTrue(view.isHidden) // <- this assertion always fails, cause `isFinished` inside the completion handler is always `false`.
        XCTAssertEqual(view.alpha, 0.0, accuracy: CGFloat.ulpOfOne)
    


UIViewTests.defaultTestSuite.run()

断言XCTAssertTrue(view.isHidden) 总是失败。此外,日志语句输出:

Date before 2019-05-20 23:30:35 +0000
Date completed 2019-05-20 23:30:35 +0000

所以基本上动画会立即被杀死。

【问题讨论】:

请分享代码 抱歉,我添加了一个游乐场示例???? 所以从你之前的描述来看:你的实际测试并没有调用动画,对吧?相反,它会调用您的分机?从您添加的代码中很难判断。 是的,我已将扩展程序中的代码直接复制到测试用例中,以使其更简单。 基本上,我想看看你要测试的代码。 【参考方案1】:

要使用正确的标志完成动画,视图需要在可见的 UIWindow 中。

let window = UIWindow()
window.addSubview(view)
window.isHidden = false

这样,您的测试就成功了。但是 UIKit 不会在测试结束时不给运行循环额外的刺激就清理窗口。所以添加

func tearDown() 
    super.tearDown()
    RunLoop.current.run(until: Date())

然后窗口(以及其中的任何内容)将被释放。

现在它正在运行,您可以通过缩短持续时间来节省时间。我使用 duration: 0.001 将测试时间缩短到 23 毫秒

【讨论】:

非常感谢您的帮助!似乎视图必须附加到当前可见的UIWindow,才能使动画正常工作。 ``` let window = UIWindow() window.makeKeyAndVisible() let view = UIView() window.addSubview(view) ``` 也有效。无论如何,我不想创建第二个键窗口,所以我选择了UIApplication.shared.keyWindow(可选选项较少)。再次感谢您的帮助:) 出色的跟进。我将使用您的信息更新我的答案,以便其他读者更容易。

以上是关于UIView.animateWithDuration:animations:completion: 在 XCTest 中被取消的主要内容,如果未能解决你的问题,请参考以下文章