Swift viewDidLoad加载后测试中未设置XCTest单元测试数据响应

Swift viewDidLoad加载后测试中未设置XCTest单元测试数据响应,swift,unit-testing,swift3,alamofire,xctest,Swift,Unit Testing,Swift3,Alamofire,Xctest,我正在尝试编写单元测试,目前我正在尝试测试一个viewController,它在viewDidLoad()中接收数据,数据是在alamofire请求后设置的。问题是,在我的测试函数中,当我检查成功请求后应填充10个元素的数组时,它是0。我已经检查了测试中是否没有执行viewDidLoad(),但应该是这样,因为当我只是将元素添加到请求之外的另一个数组中时,特定的测试工作正常。我想,这和我的请求有关,我到目前为止还没有找到答案 下面是代码(帮助我执行viewController的viewDidLo

我正在尝试编写单元测试,目前我正在尝试测试一个viewController,它在
viewDidLoad()
中接收数据,数据是在alamofire请求后设置的。问题是,在我的测试函数中,当我检查成功请求后应填充10个元素的数组时,它是0。我已经检查了测试中是否没有执行
viewDidLoad()
,但应该是这样,因为当我只是将元素添加到请求之外的另一个数组中时,特定的测试工作正常。我想,这和我的请求有关,我到目前为止还没有找到答案

下面是代码(帮助我执行viewController的viewDidLoad()):

ViewController简化版

class ViewController: UIViewController {

  var itemsFromRequest: [Int] = []
  var itemsWithoutRequest: [Int] = []

  override func viewDidLoad() {
    super.viewDidLoad()

    // array with 10 elements
    itemsWithoutRequest = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    Alamofire.request(url: URLConvertible).responseJSON { response in
      //...error handling, parsing etc.

      // set array after successful response
      self.itemsFromRequest = responseData
    }
  }
}
ViewControllerTests类:

class ViewControllerTests: XCTestCase {

  var viewController: ViewController!

  override func setUp() {
    super.setUp()

    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    viewController = storyboard.instantiateViewController(withIdentifier: "ViewController") as! ViewController
    // trigger viewDidLoad() of viewController
    let _ = viewController.view
  }

  func testItemArraysHaveTenItems() {
    // This is successful
    XCTAssertEqual(viewController.itemsWithoutRequest.count, 10)
    // This failed with error "XCTAssertEqual failed: ("0") is not equal to ("10")"
    XCTAssertEqual(viewController.itemsFromRequest.count, 10)
  }
}
为什么第二次断言失败?

问题 在第二个断言中,您期望异步加载数据,但您同步检查它们,并且在检查它们时,网络操作尚未完成,因此它当然会失败

解决方案 在iOS上可以使用异步测试

使用示例

提示 需要指出的另一点是,测试网络操作并等待响应是一种糟糕的做法,您应该拦截网络请求并返回本地数据,而不是等待来自服务器的真实数据。(在GitHub上,有一个很好的框架可以在Swift中实现这一点:)

let testExpectation = expectation(description: "Asynchronous expectation")
let sut = SubjectUnderTest()

sut.executeAsynchronousOperation(completion: { (error, data) in
    XCTAssertTrue(error == nil)
    XCTAssertTrue(data != nil)

    testExpectation.fulfill()
})

waitForExpectations(timeout: 5, handler: .none)