【问题标题】:How to detect if iOS app is running in UI Testing mode如何检测 iOS 应用程序是否在 UI 测试模式下运行
【发布时间】:2015-11-26 00:45:28
【问题描述】:

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

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

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

【问题讨论】:

    标签: ios xcode-ui-testing


    【解决方案1】:

    我自己一直在研究这个并遇到了这个问题。我最终选择了@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 测试无关。

    【讨论】:

    • 这在 Xcode 7 中似乎对我不起作用。还有其他方法吗?
    • 启动环境现在是 NSDictionary 的克星。你现在不能有@YES。您必须改为使用字符串。
    • 快捷版:let isUITest = NSProcessInfo.processInfo().environment["isUITest"] != nil
    • 我的 AppDelegate 是用 Objective C 编写的,我的测试是用 Swift 编写的。这是唯一对我有用的解决方案。
    【解决方案2】:

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

    在您的测试中 setUp() 函数添加:

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

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

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

    使用 Xcode 7.1.1 验证。

    【讨论】:

    • 这似乎对我不起作用。从 UI 测试中启动应用程序后,NSProcessInfo 参数不包含测试字符串。 Xcode 7.3b3。
    • 在 7.3 中得到同样的东西。我在 setup 中设置了 launchArguments,但如果我在下一行断点,则 launchArguments 为空。就好像它们没有被存储一样。
    • 启动参数与我认为的环境不同。根据 Apple 文档... NSProcessInfo 有两个我们要检查的进程信息属性。第一个是“参数”:带有进程命令行参数的字符串数组第二个是“环境”:启动进程的环境中的变量名称(键)及其值。您应该注意这些之间的主要区别,即“启动进程的环境”而不是“命令行参数”。
    • 因此放置 launchArguments 是有效的(如果从命令行启动),但您还必须在代码中检查这些 launchArgs。您不能检查 processInfo().environment 字典并期望“参数”在其中。那将在 NSProcessInfo 的“参数”属性中。再次直接从 Apple Docs 中查看我上面的评论。
    • 附加启动参数而不是指定不覆盖其他可能的参数可能是个好主意:app.launchArguments.append("testMode")
    【解决方案3】:

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

    新目标

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

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

    新建构建配置

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

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

    添加重复配置:

    将它用于您的测试

    【讨论】:

      【解决方案4】:

      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。

      【讨论】:

        【解决方案5】:

        我刚刚添加了这个扩展

         @available(iOS 9, *)
         extension XCUIApplication {
        
         func test(){
           launchEnvironment = ["TEST":"true"]
           launch()
          }
         }
        

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

        【讨论】:

          【解决方案6】:

          在 Swift 3 中,您可以检查 XCInjectBundleInto 键或以 XC 开头的内容。

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

          这也适用于 OS X。

          【讨论】:

          • @Phillip Otto - Oleander 没有提到的一件事是在您的课程中导入 Foundation。
          • 检查 XCTestConfigurationFilePath 似乎有效。
          【解决方案7】:

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

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-12-29
            • 2015-04-17
            • 2017-03-08
            • 2011-06-12
            • 1970-01-01
            • 2019-11-22
            • 2020-10-25
            • 1970-01-01
            相关资源
            最近更新 更多