根据Xcode UI测试是否正在运行来定义全局变量

Eri*_*ric 2 xcode ios swift xcode-ui-testing

如何根据Xcode UI测试是否正在运行来定义全局变量?我正在尝试这样做:

#if UITESTS
    let api = StubbedAPI()
#else 
    let api = RealAPI()
#endif
Run Code Online (Sandbox Code Playgroud)

这些是全局变量,因此我无法调用NSProcessInfo.processInfo().environment或NSProcessInfo.processInfo().arguments在文件范围内.

Joe*_*tti 9

UI测试目标作为与应用程序分开的进程运行.这意味着您无法在测试目标中设置预处理器宏,并希望应用程序了解它们.测试可以与应用程序通信的唯一方法是通过processInfo您提到的两个设置.

使用这些是动态的,而您提出的解决方案是静态的.但是,仍然可以使用Apple提供给我们的工具来做你想做的事情.

首先,创建StubbedAPI和RealAPI都符合的协议.

protocol API {
    // ... //
}

class RealAPI: API {
    // ... //
}

class StubbedAPI: API {
    // ... //
}
Run Code Online (Sandbox Code Playgroud)

接下来,创建一个配置类.这将用于告诉您的代码在运行时使用哪个API.

struct Config {
    var api: APIProtocol { 
        get { 
            return UITesting() ? RealAPI() : StubbedAPI()
        }
    }
}

private func UITesting() -> Bool {
    return NSProcessInfo.processInfo().arguments.contains("UI-TESTING")
}
Run Code Online (Sandbox Code Playgroud)

然后,通过配置检索对API实现的引用.

class FooService {
    private let api = Config().api;
}
Run Code Online (Sandbox Code Playgroud)

最后,在UI Testing下启动应用程序之前设置processInfo参数.

class UITests: TestCase {
    let app = XCUIApplication()

    override func setUp() {
        super.setUp()
        app.launchArguments = ["UI-TESTING"]
        app.launch()
    }
}
Run Code Online (Sandbox Code Playgroud)

api在运行生产代码时,该属性将设置为真实API,在UI测试下运行该存根.

这种方法有一些缺点.首先,您将向生产代码中引入实​​际的"存根"API.这具有开发人员在生产中实际使用它的潜在缺点.其次,您需要创建API协议,只有一个"真实"对象实现它.不幸的是,考虑到UI测试和Swift的当前状态,这是我提出的最佳解决方案.