简体   繁体   English

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

[英]UIView.animateWithDuration:animations:completion: gets canceled in XCTest

I'm trying to unit test an extension on UIView , which calls animateWithDuration:animations:completion: .我正在尝试对UIView上的扩展进行单元测试,该扩展调用animateWithDuration:animations:completion:

Unfortunately all animations in the test case gets canceled immediately and therefore the isFinished parameter of the completion block is always false .不幸的是,测试用例中的所有动画都会立即取消,因此完成块的isFinished参数始终为false

Does anyone have an idea how to get animations working in a test case?有谁知道如何让动画在测试用例中工作?

This is my playground code:这是我的游乐场代码:

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()

The assertion XCTAssertTrue(view.isHidden) always fails.断言XCTAssertTrue(view.isHidden)总是失败。 Furthermore the log statements output:此外,日志语句输出:

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

So basically the animation is killed immediately.所以基本上动画立即被杀死。

For the animation to complete with the correct flag, the view needs to in a UIWindow that is visible.要使动画以正确的标志完成,视图需要位于可见的 UIWindow 中。

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

With this, your test succeeds.这样,您的测试就成功了。 But UIKit won't clean up the window without giving the run loop an extra kick at the very end of the test.但是 UIKit 不会在测试结束时不给运行循环一个额外的踢来清理窗口。 So add所以添加

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

Then the window (and anything in it) will be deallocated.然后窗口(以及其中的任何内容)将被释放。

Now that it's working, you can save time by reducing your duration.现在它正在运行,您可以通过减少持续时间来节省时间。 I got the test down to 23ms by using duration: 0.001我通过使用duration: 0.001将测试缩短到 23 毫秒duration: 0.001

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM