Swift TDD 和异步 URLSession - 如何测试?

标签 swift tdd

我尝试熟悉 TDD。如何测试异步的 URLSession 调用?哪个 XCAssert 更适合在哪个阶段使用?

我的第一个想法是创建一个函数,其中包含 URLSession,并在该函数中将 bool 标志设置为 true,然后在 XCAssertTrue 中对其进行测试。或者另一个想法是在调用包含 USLSession 代码的函数后同步返回假数据。

最佳答案

好问题。我认为它可以分为两部分,第一部分是关于如何使用 XCTest 测试异步代码,第二部分是关于您建议的策略。

异步代码的问题是它在与测试不同的线程上运行,这导致测试在异步调用之后继续进行,并在异步调用完成之前完成。

XCTest 框架提供了一个专为此用例构建的 waitForExpectationsWithTimeout:handler 函数。它允许您等待异步调用完成,然后才检查其结果。

你可以这样使用它:

import XCTest
@testable import MyApp

class CallbackTest: XCTestCase {

  func testAsyncCalback() {
    let service = SomeService()

    // 1. Define an expectation
    let expectation = expectationWithDescription("SomeService does stuff and runs the callback closure")

    // 2. Exercise the asynchronous code
    service.doSomethingAsync { success in
      XCTAssertTrue(success)

      // Don't forget to fulfill the expectation in the async callback
      expectation.fulfill()
    }

    // 3. Wait for the expectation to be fulfilled
    waitForExpectationsWithTimeout(1) { error in
      if let error = error {
        XCTFail("waitForExpectationsWithTimeout errored: \(error)")
      }
    }
  }
}

您可以在 this blog post 中阅读有关该方法的更多信息。 完全公开,我写的。

现在,关于您的建议:

My first thought was to create a function, that has URLSession inside it, and inside this function set bool flag to true and then test it in XCAssertTrue.

好主意。这是测试是否实际调用异步回调的好方法。唯一要记住的是测试需要等待异步调用运行,否则它总是会失败。

使用上面的技术你可以写:

let service = SomeService()
var called = false

let expectation = expectationWithDescription(
    "The callback passed to SomeService is actually called"
)

service.doSomethingAsync { _ in
  called = true
  expectation.fulfill()
}

waitForExpectationsWithTimeout(1) { error in
  if let error = error {
    XCTFail("waitForExpectationsWithTimeout errored: \(error)")
  }

  XCTAssertTrue(called)
}

Or another thought was to return fake data synchronously after calling function which contains URLSession code.

这是另一个好主意。将软件分解成只做一件事的组件,对它们进行彻底的隔离测试,最后通过一些强调快乐和最常见的失败路径的集成测试来测试它们是否一起工作。

既然您提到了 URLSession,我想就涉及网络的单元测试代码留下警告说明。在单元测试中进行真实的网络调用通常不是一个好主意。事实上,它将测试绑定(bind)到网络可用并返回预期结果的事实,同时也使它们变慢。

在单元级别,我们希望我们的测试是独立的、确定的和快速的(更多关于这个 here )。使用网络与这些目标不一致。

避免访问网络的一个好方法是对其进行 stub ,方法是将 URLSession 包装到协议(protocol)中,然后在测试中使用符合它的伪造,或者使用类似 OHHTTPStubs 的库。 This post 更详细,再次全面披露,我也写了这个。

希望这对您有所帮助。对异步代码进行单元测试并非易事,您应该耐心等待并在出现问题时不断提问 :)

关于Swift TDD 和异步 URLSession - 如何测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40330692/

相关文章:

Swift 搜索栏 - 使用 Alamofire 请求更新表格 View

ios - 我们可以在 native iOS 应用程序中创建 localhost

带有 x-www-form-urlencoded 的 iOS Swift POST api

ruby-on-rails - Rails:使用 ActiveRecord::StatementInvalid: PG::NotNullViolation: ERROR 测试失败

unit-testing - 对编译器进行单元测试

swift - 使用 Binding 确定 SwiftUI 中的字符串更改

ios - 快速枚举类

javascript - 我如何测试 Jasmine 中的值是 "greater than or equal to"?

.net - 使用 asp.net 2.0 进行测试驱动开发的最佳工具是什么?

swift - 单元测试错误说参数不匹配任何可用的重载