51

我希望我的应用程序在 UI 测试模式下运行时运行特殊代码(例如重置其状态)。我查看了应用程序从 UI 测试运行时设置的环境变量,并且没有任何明显的参数可以区分应用程序正常运行与 UI 测试中运行。有没有办法找出来?

我不满意的两个解决方法是:

  1. 设置XCUIApplication.launchEnvironment一些我稍后在应用程序中检查的变量。这不好,因为您必须在setUp每个测试文件的方法中设置它。我尝试从方案设置中设置环境变量,但在运行 UI 测试测试时不会传播到应用程序本身。
  2. 检查环境变量是否存在__XPC_DYLD_LIBRARY_PATH。这看起来很 hacky,并且可能只是因为我们如何设置目标构建设置的巧合而现在才起作用。
4

7 回答 7

59

我自己一直在研究这个并遇到了这个问题。我最终选择了@LironYahdav 的第一个解决方法:

在您的 UI 测试中:

- (void)setUp
{
    [super setUp];

    XCUIApplication *app = [[XCUIApplication alloc] init];
    app.launchEnvironment = @{@"isUITest": @YES};
    [app launch];
}

在您的应用中:

NSDictionary *environment = [[NSProcessInfo processInfo] environment];
if (environment[@"isUITest"]) {
    // Running in a UI test
}

@JoeMasilotti 的解决方案对单元测试很有用,因为它们与被测试的应用程序共享相同的运行时,但与 UI 测试无关。

于 2015-10-09T12:19:52.580 回答
19

我没有成功设置启动环境,但让它与启动参数一起工作。

在您的测试setUp()功能中添加:

let app = XCUIApplication()
app.launchArguments = ["testMode"]
app.launch()

在您的生产代码中添加如下检查:

let testMode =  NSProcessInfo.processInfo().arguments.contains("testMode")
if testMode {
  // Do stuff
}

使用 Xcode 7.1.1 验证。

于 2015-11-24T10:11:28.480 回答
6

Swift 3 基于以前的答案。

class YourApplicationUITests: XCTestCase {

    override func setUp() {
        super.setUp()

        // Put setup code here. This method is called before the invocation of each test method in the class.

        // In UI tests it is usually best to stop immediately when a failure occurs.
        continueAfterFailure = false
        // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
        let app = XCUIApplication()
        app.launchArguments = ["testMode"]
        app.launch()

        // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
    }

    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        super.tearDown()
    }

    func testExample() {
        // Use recording to get started writing UI tests.
        // Use XCTAssert and related functions to verify your tests produce the correct results.
    }

}


extension UIApplication {
    public static var isRunningTest: Bool {
        return ProcessInfo().arguments.contains("testMode")
    }
}

然后只需在您的代码中调用 UIApplication.isRunningTest 即可。

于 2017-08-29T18:54:25.880 回答
6

您可以为此使用预处理器宏。我发现你有几个选择:

新目标

制作应用程序目标的副本并将其用作要测试的目标。此目标副本中的任何预处理器宏都可以在代码中访问。

一个缺点是您还必须向复制目标添加新的类/资源,有时很容易忘记。

新的构建配置

复制Debug构建配置,将任何预处理器宏设置为此配置并将其用于您的测试(请参见下面的屏幕截图)。

一个小问题:每当您想记录UI 测试会话时,您都需要更改Run以使用新的测试配置。

添加重复配置:

添加重复的conf

将其用于您的测试

将它用于您的*测试*

于 2015-10-18T12:04:37.113 回答
3

我刚刚添加了这个扩展

 @available(iOS 9, *)
 extension XCUIApplication {

 func test(){
   launchEnvironment = ["TEST":"true"]
   launch()
  }
 }

所以我可以只使用 test() 而不是 launch()

于 2015-12-18T03:23:07.540 回答
2

在 Swift 3 中,您可以检查XCInjectBundleInto密钥或以 . 开头的内容XC

let isInTestMode = ProcessInfo.processInfo.environment["XCInjectBundleInto"] != nil

这也适用于 OS X。

于 2017-01-24T15:00:03.237 回答
0

我的解决方案几乎与上面的 Ciryon相同,除了对于我的基于 macOS 文档的应用程序,我必须在参数名称前添加一个连字符:

let app = XCUIApplication()
app.launchArguments.append("-Testing")
app.launch() 

...否则,“测试”最终被解释为启动应用程序时要打开的文档的名称,所以我收到了错误警报:

在此处输入图像描述

于 2019-03-25T09:10:22.340 回答