4

我有一个正在单元测试的 Swift 类。该类的主要目的是进行 HTTP 调用。我刚刚使用Mockingjay完成了对所有网络请求的模拟,但我想确保今后我不会忘记模拟未来的请求。当我进行最初的模拟时,我用一个不起作用的基本 URL 替换了我正在使用的基本 URL,但我想只在我的测试中保留它。被测类如下所示:

public class MyWebServiceWrapper {
    ...

    public class var baseURL: String {
        return "https://api.thesite.com"
    }

    ...
}

我尝试使用Objective-C类OCMock来替换baseURL'上面-我宁愿不调酒,尤其是因为否则我不需要该类成为子类)。NSObjectbaseURLNSObject

这是我用来执行尝试混合的代码,但没有效果。对于以下两种尝试的解决方案,我像这样重写了我的测试类(因​​为看起来这两种方法都不适用于 Swift 属性或纯 Swift 类):

@objc public class MyWebServiceWrapper: NSObject {
    ...

    public class var baseURL: String {
        return baseURLValue()
    }

    public class func baseURLValue() -> String {
        return "https://api.thesite.com"
    }

    ...
}

这是我的精彩尝试(在 Swift 中)。根据日志,我else每次都点击该语句,以防它有助于弄清楚发生了什么。

extension MyWebServiceWrapper {

    public override class func initialize() {
        struct Static {
            static var token: dispatch_once_t = 0
        }

        if self !== MyWebServiceWrapper.self {
            return
        }

        dispatch_once(&Static.token) {
            NSLog("Replacing MyWebServiceWrapper base URL...")
            let originalSelector = #selector(baseURLValue)
            let swizzledSelector = #selector(networkFreeBaseURL)

            guard let klass = object_getClass(self) else {
                return
            }

            let originalMethod = class_getClassMethod(klass, originalSelector)
            let swizzledMethod = class_getClassMethod(klass, swizzledSelector)

            let didAddMethod = class_addMethod(klass, originalSelector,
                                               method_getImplementation(swizzledMethod),
                                               method_getTypeEncoding(swizzledMethod))

            if didAddMethod {
                NSLog("MyWebServiceWrapper method added")
                class_replaceMethod(klass, swizzledSelector, method_getImplementation(originalMethod),
                                    method_getTypeEncoding(originalMethod))
            } else {
                method_exchangeImplementations(originalMethod, swizzledMethod)
                NSLog("MyWebServiceWrapper implementation replaced")
            }
        }
    }

    class func networkFreeBaseURL() -> String {
        return "https://tests-shouldnt-hit-the-network.com"
    }

}

这就是我尝试使用 OCMock(在 Objective-C 中)替换该方法的方式。该代码在我的单元测试配置期间被调用。

id wrapperMock = OCMClassMock([MyWebServiceWrapper class]);
OCMStub(ClassMethod([wrapperMock baseURLValue])).andReturn(@"https://tests-shouldnt-hit-the-network.com");

实现从 中返回无效值的目标的正确方法是baseURL什么?

4

1 回答 1

1

我对此并不完全满意(换句话说,我仍然喜欢其他答案),因为它需要修改被测类的代码,但这就是我最终得到的。它完成了工作,并且不容易被非测试代码滥用,因为我创建了覆盖变量internal

public class MyWebServiceWrapper {
    ...

    /// Only use for testing!
    internal static var baseURLOverride: String?

    public class var baseURL: String {
        return baseURLOverride ?? "https://api.thesite.com"
    }

    ...
}

从我的测试配置内部:

@testable
import MyFramework

...

// Inside test configuration
MyWebServiceWrapper.baseURLOverride = "https://tests-shouldnt-hit-the-network.com"
于 2016-05-05T17:30:09.237 回答