在 Swift 单元测试中,我在 App 和单元测试目标之间遇到类转换错误
Posted
技术标签:
【中文标题】在 Swift 单元测试中,我在 App 和单元测试目标之间遇到类转换错误【英文标题】:In Swift Unit Tests I'm getting a class cast error between App and Unit Test Targets 【发布时间】: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 目标将导入所有应用程序目标类。如果我需要复制测试目标中的类,那么单元测试的整个想法就失去了意义。
应用程序文件(以及它们包含的类和其他类型)不会自动导入到单元测试目标中。当您创建一个新文件时,您指定您希望它成为哪些目标。如果您没有添加您的单元测试目标,您可以稍后从检查器添加它(选择文件,打开检查器并勾选您的测试目标)。
我知道这一点。在与案例相关的情况下,所有文件:结构、视图控制器、提供程序,甚至故事板都包含在测试目标中。
【参考方案1】:
好的,经过长时间的研究而没有任何回应,我“找到”了我的问题的解决方案。使用this*** 帖子的信息,我尝试了一些猴子业务,错误消失了。
实际上,解决问题的方法是禁用 UnitTest Target 的 Main Storyboard。我启用它是因为问题中列出了 instantiateWithId
方法。据我了解,有必要将其链接到测试目标以在测试目标使用的代码中对其进行实例化,但由于某种原因,这是错误的做法。
现在它正在工作,我可以继续使用我的 Swift TDD。但是,如果有人能解释我为什么这是测试的正确配置,我保证为我的下一个孩子提供你的名字。
感谢和问候。
【讨论】:
实际上,我无法继续使用 TDD,因为现在我的代码没有找到 Main Storyboard,因为它没有链接到 UnitTestTarget。就像我认为它可能发生的那样,这就是我从一开始就链接它的原因。以上是关于在 Swift 单元测试中,我在 App 和单元测试目标之间遇到类转换错误的主要内容,如果未能解决你的问题,请参考以下文章