Swift MVVM测试策略和代码覆盖率问题

时间:2017-08-31 00:54:52

标签: swift xcode unit-testing mvvm mocking

在使用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导入BoosApp 添加到单元测试中,以便可以解析测试中的视图模型。当我这样做时,我收到以下错误:

无法转换类型' BoosTests.BoosViewModelTests。(testGetUnlinkedBoosHappyPath() - >())。(FauxDataManager#1)' (0x11f673d18)到' Boos.BoosDataManager' (0x10444b128)。 8月30日20:43:01支付[19025]:无法转换类型' BoosTests.BoosViewModelTests。(testGetUnlinkedBoosHappyPath() - >())。(FauxDataManager#1)' (0x11f673d18)到' Boos.BoosDataManager' (0x10444b128)。

我不确定我错过了什么。有没有办法让这个场景有效,或者我在测试代码之外创建了多个数据管理器?

1 个答案:

答案 0 :(得分:0)

最终,我发现主要问题是视图模型和数据管理器已经以某种方式被添加到测试目标中。从测试目标中删除它后,我能够进行一些小的更改,一切运行正常。 FYI。