【发布时间】:2017-08-31 00:54:51
【问题描述】:
我在使用 Xcode 为 MVVM 环境中的视图模型生成代码覆盖率时遇到了问题。
我们的基本设置是视图控制器向视图模型发出请求,然后视图模型调用与 Web 服务对话的数据管理器上的方法。
我想出了一种我认为是相当优雅的方法来测试视图模型,方法是创建一个假数据管理器,它继承了实际数据管理器并覆盖了 VM 调用的函数。
问题在于,要使其正常工作,VM 必须是应用程序目标和测试目标的一部分。这样做的一个明显副作用是,即使单元测试通过,也不会为属于两个或多个目标的项目生成代码覆盖率。项目中启用了代码覆盖率。
这是一个摘录的视图模型:
import Foundation
class BoosViewModel: BaseViewModel {
convenience override init() {
self.init(dataManager: BoosDataManager(), andModel: nil)
}
func getUnlinkedBoos(_ cardType: CardType) {
(dataManager as! BoosDataManager).getUnlinkedBoos(cardType) { result, error in
...stuff happens here...
}
}
}
...和数据管理器
class BoosDataManager: DataManager {
static let SharedInstance: BoosDataManager = {
var manager = BoosDataManager()
return manager
}()
func getUnlinkedBoos(_ cardType: CardType = .loyalty, completion: @escaping ((_ result: BoosModel?, _ error: NSError?) -> Void)) {
...stuff happens here...
}
}
...和测试
class BoosViewModelTests: XCTestCase {
func testGetUnlinkedBoosHappyPath() {
class FauxDataManager: BoosDataManager {
override func getUnlinkedBoos(_ cardType: CardType = .loyalty, completion: @escaping ((_ result: BoosModel?, _ error: NSError?) -> Void)) {
...stuff happens here...
}
}
let viewModel = BoosViewModel()
let dataManager = FauxDataManager()
viewModel.dataManager = dataManager
viewModel.getUnlinkedBoos(.loyalty)
XCTAssertTrue(testObserver.updated)
XCTAssertEqual(testObserver.newViewModel.getBoos().count, 1)
}
}
如前所述,此场景中的单元测试成功完成,但未生成单元覆盖率。
我有较旧的测试,其中我实际上创建了一个外部假数据管理器类供测试使用,被测类不是测试目标的一部分,并且覆盖工作正常。
这样做的缺点是我必须创建多个数据管理器来处理返回的特定情况。如果我不能封装这些类,我需要创建一堆快速数据管理器,每个场景一个。
这就是我想出内部类的原因。
现在,如果我从测试目标中删除正在测试的视图模型,就会出现问题。完成此操作后,我将 @testable import BoosApp 添加到单元测试中,以便可以解析被测视图模型。当我这样做时,我收到以下错误:
无法将“BoosTests.BoosViewModelTests.(testGetUnlinkedBoosHappyPath () -> ()).(FauxDataManager #1)”(0x11f673d18) 类型的值转换为“Boos.BoosDataManager”(0x10444b128)。 8 月 30 日 20:43:01 Pay[19025]:无法将类型“BoosTests.BoosViewModelTests.(testGetUnlinkedBoosHappyPath () -> ()).(FauxDataManager #1)”(0x11f673d18) 的值转换为“Boos.BoosDataManager”(0x10444b128) )。
我不确定我错过了什么。有没有办法让这个场景工作,还是我被困在测试代码之外创建多个数据管理器?
【问题讨论】:
标签: swift xcode unit-testing mvvm mocking