UnitTest - 使用NSPredicate

时间:2017-10-24 15:32:04

标签: ios swift xcode unit-testing

我在使用最新的XCTestCase功能进行单元测试时遇到了麻烦。

这就是我所拥有的

viewModel.getLocations()
let loaded = NSPredicate(format: "boolAttribute == %@", NSNumber(value: true))
let dataLoaded = XCTNSPredicateExpectation(predicate: loaded, object: viewModel.dataExist())
wait(for: [dataLoaded], timeout: 5)

所以我需要等待网络加载才能继续,它确实等待。但它总是得到时间但是,在检查我的变量时,数据已经设定。

最后,如果我抓住等待的结果,测试将成功,即使timedOut也会继续,但它只是一个黑客......

感谢您的帮助

2 个答案:

答案 0 :(得分:1)

最佳做法是在单元测试时不使用网络呼叫。这就是使用模拟数据的依赖注入。

我曾经就此进行过讨论,示例代码可以在这里找到:https://github.com/karnett/MVVM

要扩展您的实际问题 - 我使用这两个在堆栈溢出Universe中浮动的函数:

func wait(_ duration: TimeInterval, object: XCUIElement)
{

    //waits for condition to be met when changing views before continuing tests.
    _ = self.expectation(
        for: NSPredicate(format: "exists == 1"),
        evaluatedWith: object,
        handler: nil)
    self.waitForExpectations(timeout: duration, handler: nil)
}

func wait(_ duration: TimeInterval, object: XCUIElementQuery, count: Int)
{
    //waits for condition to be met when changing views before continuing tests.
    _ = self.expectation(
        for: NSPredicate(format: "self.count = \(count)"),
        evaluatedWith: object,
        handler: nil)
    self.waitForExpectations(timeout: duration, handler: nil)
}

你可以通过以下方式打电话给他们:

let emailTextField = app.textFields["Email"]

self.wait(2.0, object: app.textFields["Email"])

如果您的视图未按x时间加载,则单元测试应该失败。存在单元测试以确保您1)没有破坏任何东西,2)验证用户要求,以及3)确保用户具有良好的体验。

答案 1 :(得分:1)

重要的是要强调 NSPredicate 与 ObjC 兼容的对象、函数和属性一起工作,这意味着针对给定谓词评估的对象必须是 NSObject 类型的子类,并且测试的属性或函数必须用 @objc 属性标记。

class ViewModel: NSObject {
    var _counter: Int = 0
    @objc var counter: Int {
        _counter += 1
        debugPrint(_counter)
        return _counter
    }
    
    var _counter2: Int = 0
    @objc func counter2() -> Int {
        _counter2 -= 1
        debugPrint(_counter2)
        return _counter2
    }
}

func testPredicateFormat() {
    let model = ViewModel()
    
    let counterValue = NSPredicate(format: "counter > 5")
    let dataLoaded = XCTNSPredicateExpectation(predicate: counterValue, object: model)
    wait(for: [dataLoaded], timeout: 10)
    
    let counterValue2 = NSPredicate(format: "counter2 < -5")
    let dataLoaded2 = XCTNSPredicateExpectation(predicate: counterValue2, object: model)
    wait(for: [dataLoaded2], timeout: 10)
}