在 Swift TDD 中模拟 NSBundle

AJ9*_*AJ9 4 tdd unit-testing mocking ios swift

是否可以模拟应用程序 NSBundle 以在 TDD 期间返回可预测的结果?

例如:

我想测试我的应用程序在文件未保存到 NSBundle 时是否进行处理:

//Method to test
func getProfileImage() -> UIImage {
    if let profileImagePath = getProfilePhotoPath() {
        UIImage(contentsOfFile: profileImagePath)
    }
    return UIImage(named: "defaultProfileImage")
}

private func getProfilePhotoPath() -> String? {
    return NSBundle.mainBundle().pathForResource("profileImage", ofType: "png")
}
Run Code Online (Sandbox Code Playgroud)

是否可以模拟 NSBundle.mainBundle() 为 pathForResource 返回 false ?

Jon*_*eid 5

就目前而言,NSBundle.mainBundle()这是一个硬编码的依赖项。我们想要的是能够指定任何包,也许将 mainBundle 作为默认值。答案是依赖注入。让我们使用构造函数注入的首选形式,并利用 Swift 的默认参数:

class ProfileImageGetter {
    private var bundle: NSBundle

    init(bundle: NSBundle = NSBundle.mainBundle()) {
        self.bundle = bundle
    }

    func getProfileImage() -> UIImage {
        if let profileImagePath = getProfilePhotoPath() {
            return UIImage(contentsOfFile: profileImagePath)!
        }
        return UIImage(named: "defaultProfileImage")!
    }

    private func getProfilePhotoPath() -> String? {
        return bundle.pathForResource("profileImage", ofType: "png")
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,测试可以实例化 ProfileImageGetter 并指定它喜欢的任何包。这可能是测试包,也可能是假包。

指定测试包将使您遇到 profileImage.png 不存在的情况。

指定一个 fake 可以让你存根调用的结果pathForResource()