是否可以在 Xcode 7 自动化 UI 测试中存根 HTTP 请求?

Posted

技术标签:

【中文标题】是否可以在 Xcode 7 自动化 UI 测试中存根 HTTP 请求?【英文标题】:Is it possible to stub HTTP requests in Xcode 7 automated UI tests? 【发布时间】:2015-09-28 16:22:14 【问题描述】:

我一直在尝试使用 OHHTTPStubs 之类的工具在 Xcode 7 自动化 UI 测试中拦截和存根/模拟 HTTP 请求,但没有成功。

以下是我如何尝试在 UI 测试文件的 setUp 方法中使用 OHHTTPStubs 捕获任何 HTTP 请求的示例:

override func setUp() 
  super.setUp()

  let matcher: OHHTTPStubsTestBlock =  (request) -> Bool in
    return true
  

  OHHTTPStubs.stubRequestsPassingTest(matcher)  (response) -> OHHTTPStubsResponse! in
    return OHHTTPStubsResponse.init()
  

UI 测试的工作方式是否可以防止这种情况发生?有没有人能够做到这一点?

【问题讨论】:

嘿,你最终找到解决方案了吗? 是的,刚刚添加在下面。 要动态存根 HTTP 请求,您可以使用 SBTUITestTunnel,查看我的回答 here 【参考方案1】:

正如 Martijn 正确指出的那样,由于 UI 测试的工作方式,您无法在运行时直接与应用程序交互,因此任何 HTTP 模拟或对 XCUITestCase 中的 NSUserDefaults 之类的操作都不会影响您的应用程序。

如果您确实需要能够模拟 HTTP 或设置和拆卸您的应用程序环境以进行特定的 UI 测试,您将需要在启动应用程序之前在 @987654325 的 setUp() 方法中设置启动参数或启动环境变量@ 然后修改您的应用代码以读取启动参数或环境变量并引导测试环境。

示例测试用例

class MyTestCase: XCTestCase 

  /**
  Called before each test in this test case.
  */
  override func setUp() 
    super.setUp()

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


AppDelegate 示例

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool 

#if DEBUG
  if (NSProcessInfo.processInfo().arguments.contains("STUB_HTTP_ENDPOINTS")) 
    // setup HTTP stubs for tests
  
#endif

  return true

注意:为了在本例中使用像 OHHTTPStubs 这样的 HTTP 模拟框架,您需要使用的存根代码和任何 JSON 固定装置都需要在您的应用目标中,而不是测试目标。

这是一个非常有用的话题:https://github.com/AliSoftware/OHHTTPStubs/issues/124

【讨论】:

听起来虽然这确实允许您实现存根,但您还将发布一个应用程序,其中包含存根“代码”和存根网络文件。这可能是一件非常糟糕的事情。 我将存根代码包装在对 DEBUG 预处理器宏的 if 检查中,因此存根代码实际上不应进入 App Store 构建。我已经更新了代码示例以显示这一点。感谢您指出这一点。【参考方案2】:

UI 测试在与您的应用程序不同的实例中运行。虽然您可能可以使用应用程序中的类,但它们只是一个副本。

在您的应用程序中,您可以使用此处提供的解决方案检测您是否在 UI 测试模式下运行:How to detect if ios app is running in UI Testing mode

我个人选择了原帖中提到的launchEnvironment解决方案;我的设置如下所示:

override func setUp() 
    super.setUp()

    let app = XCUIApplication()
    app.launchEnvironment["TEST"] = "1"
    app.launch()

我的一个单例实例化器(称为 RealmManager)看起来像这样(用于实例化 Realm 数据库):

func realm() -> Realm 
    let dic = NSProcessInfo.processInfo().environment
    if dic["TEST"] != nil 
        return try! Realm(configuration: Realm.Configuration(inMemoryIdentifier: "test"))
    
    return try! Realm()

如果你不喜欢重复,但你可能已经在重复 XCUIApplication().launch(),你总是可以创建一个扩展 XCTestCase 的自定义测试用例类,用这个添加覆盖 setUp,然后在你所有的测试类。

【讨论】:

如何执行不同的测试用例?例如,如果我想测试登录成功和登录失败,最好的做法是存根这两个不同的响应......你如何用你的逻辑处理这样的事情?我只能理解我是在“应用领域”还是“测试领域”中运行,但我无法处理不同的“测试领域”响应。 假用户? “用户”+“错误密码”=失败,“用户”+“密码”=成功。

以上是关于是否可以在 Xcode 7 自动化 UI 测试中存根 HTTP 请求?的主要内容,如果未能解决你的问题,请参考以下文章

是否可以为 xcode UI 测试自动设置位置?

XCode 7 UI 测试 - 可用的操作

在 UI 测试期间,如何使用 Xcode 7 截取我的 UI 截图?

在 Xcode 7.0.1 中进行 UI 测试时,是不是可以使用 Swift 滚动到 Element()?

XCode 7 中的 UI 测试文档 [关闭]

Xcode 7 中的特定 UI 测试