【发布时间】:2017-07-01 16:44:40
【问题描述】:
在 iOS 10 Swift 3 应用程序中,我正在尝试使用 NotificationCenter 测试 ViewController。
在我的 ViewController 初始化时,我向提供者查询数据并接收同步响应。然后,提供者尝试使用对 web 的异步调用来刷新数据,如果它被更改,则发送将被 ViewController 捕获的通知。这是我的 ViewController 初始化的一部分:
class func instantiateWithId(_ id: String, provider: DataProvider) -> MyViewController {
let storyboard = UIStoryboard(name: "Main", bundle: Bundle(for:MyViewController.self));
let controller = storyboard.instantiateViewController(withIdentifier: "ViewControllerId") as! MyViewController;
controller.dataProvider = provider;
controller.objectId = id;
controller.object = controller.dataProvider!.getObject(id: id, completion: controller.refreshObject);
return controller;
}
初始化后,我注册了工作正常的通知观察器:
NotificationCenter.default.addObserver(self, selector: #selector(self.catchNotification), name: NotificationName, object: nil);
这是在 ViewController 中处理通知的函数。它工作正常:
func catchNotification(notification: NSNotification) -> Void {
guard (notification.name == NotificationName) else {return;}
let info = notification.userInfo as! [String: Any];
if info.count > 0 {
guard (info[objectId] != nil) else {return;}
if let value = info[objectId] as! MyCustomStruct? {
self.refreshData(updated: value);
}
}
}
在 Provider 中,一旦我收到来自 web 的异步响应,我就会在 userInfo 中发送带有新数据的通知:
var dict = Dictionary<String, myCustomStruct>();
dict.updateValue(newData, forKey: newData.objectId);
let msg = Notification(name: NotificationName, object: nil, userInfo: dict)
NotificationCenter.default.post(msg);
上面的所有代码都可以正常工作,但是在我的单元测试中,当我的 ViewController 捕获到通知说不能将 UnitTest 目标的 myCustomStruct 转换为应用程序目标中的 myCustomStruct 时,我得到一个错误:
Could not cast value of type ‘ApplicationUnitTests.MyCustomStruct’ (0x1161fa828) to ‘Application. myCustomStruct' (0x1057fd6d0).
我已经检查过了,两个目标都可以使用 CustomStruct。
这是我的测试:
func testViewControllerInitialization() {
let fixture = MockDataProvider();
let sutId = fixture.testId;
let sut = MyViewController.instantiateWithId(sutId, provider: fixture)
_ = sut.view;
XCTAssertNotNil(sut, "SUT not initialized");
XCTAssertNotNil(sut.object, "Object Not Loaded!");
XCTAssertEqual(sutId, sut.object!.objectId, "Differente ObjectId expected!");
let newValue = "changed";
var nextFixture = fixture.getObject(objectId: sutId, completion: {(result) in return;});
nextFixture.name = newValue;
fixture.refreshObject(newData: nextFixture); <- This function send the notification
sleep(1);
XCTAssertEqual(newValue, sut.object!.name);
}
【问题讨论】:
-
该错误完全描述了问题:应用程序需要
Application.myCustomStruct,而您正在发送ApplicationUnitTests.MyCustomStruct。你不能在测试中使用Application.myCustomStruct吗? -
重点是:我没有 ApplicationUnitTests.MyCustomStructs。我只有 Application.myCustomStruct。据我了解,ApplicationUnitTests 目标将导入所有应用程序目标类。如果我需要复制测试目标中的类,那么单元测试的整个想法就失去了意义。
-
应用程序文件(以及它们包含的类和其他类型)不会自动导入到单元测试目标中。当您创建一个新文件时,您指定您希望它成为哪些目标。如果您没有添加您的单元测试目标,您可以稍后从检查器添加它(选择文件,打开检查器并勾选您的测试目标)。
-
我知道这一点。在与案例相关的情况下,所有文件:结构、视图控制器、提供程序,甚至故事板都包含在测试目标中。
标签: ios unit-testing swift3 xcode8