我在使用最新的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也会继续,但它只是一个黑客......
感谢您的帮助
答案 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)
}