iOS 自动化测试 - 使用HTTPClientSpy进行网络请求测试的实例分析

89 阅读3分钟

简述

在单元测试或集成测试中,使用 HTTPClientSpy 是一种常见的做法。通过替换真实的 HTTP 客户端,我们可以模拟对外部服务的请求和响应,确保我们的代码在不同场景下的行为正确。

设置测试环境

在测试中,我们需要对请求进行干预,以便控制和验证网络请求的行为。在这个测试用例中,首先导入了 XCTestExampleProject 模块,然后定义了一个名为 URLSessionHTTPClientTests 的测试用例类。

override func setUp() {
    super.setUp()
    URLProtocolStub.startInterceptingRequests()
}

override func tearDown() {
    super.tearDown()
    URLProtocolStub.stopInterceptionRequests()
}

具体方法

static func startInterceptingRequests() {
    URLProtocol.registerClass(URLProtocolStub.self)
}

static func stopInterceptionRequests() {
    URLProtocol.unregisterClass(URLProtocolStub.self)
    stub = nil
    requestObserver = nil
}

setUp 方法中,我们启动对请求的拦截,以便在测试过程中观察和控制请求。在 tearDown 方法中,我们停止拦截请求,并清理相关设置。

测试方法

测试方法是测试用例类的核心部分,用于测试被测代码的各种行为和情况。以下是几个关键的测试方法及其解释。

取消网络请求的测试

通过这段测试代码,我们可以确保在取消网络请求时,网络请求被正确地取消,并且返回了正确的错误。

func test_cancelGetFromURLTask_cancelsURLRequest() {
    let exp = expectation(description: "Wait for request")
    URLProtocolStub.observeRequests { _ in
        exp.fulfill()
    }

    let receivedError = resultErrorFor(taskHandler: { $0.cancel() }) as NSError?
    wait(for: [exp], timeout: 1.0)

    XCTAssertEqual(receivedError?.code, URLError.cancelled.rawValue)
}

网络请求错误处理的测试

通过这段测试代码,我们可以确保当网络请求过程中发生了错误时,网络请求能够正确地处理这种情况,并返回了预期的错误。

func test_getFromURL_failsOnRequestsError() {
    let requestError = anyNSError()

    let receivedError = resultErrorFor((data: nil, response: nil, error: requestError))

    XCTAssertNotNil(receivedError)
}

无效表示情况下的测试

这些测试确保 getFromURL 在处理不同无效输入情况下能够正确地返回错误。

func test_getFromURL_failsOnAllInvalidRepresentationCases() {
    XCTAssertNotNil(resultErrorFor((data: nil, response: nil, error: nil)))
    XCTAssertNotNil(resultErrorFor((data: nil, response: nonHTTPURLResponse(), error: nil)))
    XCTAssertNotNil(resultErrorFor((data: anyData(), response: nil, error: nil)))
    XCTAssertNotNil(resultErrorFor((data: anyData(), response: nil, error: anyNSError())))
    XCTAssertNotNil(resultErrorFor((data: nil, response: nonHTTPURLResponse(), error: anyNSError())))
    XCTAssertNotNil(resultErrorFor((data: nil, response: anyHTTPURLResponse(), error: anyNSError())))
    XCTAssertNotNil(resultErrorFor((data: anyData(), response: nonHTTPURLResponse(), error: anyNSError())))
    XCTAssertNotNil(resultErrorFor((data: anyData(), response: anyHTTPURLResponse(), error: anyNSError())))
    XCTAssertNotNil(resultErrorFor((data: anyData(), response: nonHTTPURLResponse(), error: nil)))
}

成功获取数据的测试

这些测试确保 getFromURL 在处理有效 HTTP 响应和数据情况下能够正确返回结果。

func test_getFromURL_succeedsOnHTTPURLResponseWithData() {
    let data = anyData()
    let response = anyHTTPURLResponse()

    let receivedValues = resultValuesFor((data: data, response: response, error: nil))

    XCTAssertEqual(receivedValues?.data, data)
    XCTAssertEqual(receivedValues?.response.url, response.url)
    XCTAssertEqual(receivedValues?.response.statusCode, response.statusCode)
}

func test_getFromURL_succeedsWithEmptyDataOnHTTPResponseWithNilData() {
    let response = anyHTTPURLResponse()

    let receivedValues = resultValuesFor((data: nil, response: response, error: nil))

    let emptyData = Data()
    XCTAssertEqual(receivedValues?.data, emptyData)
    XCTAssertEqual(receivedValues?.response.url, response.url)
    XCTAssertEqual(receivedValues?.response.statusCode, response.statusCode)
}

数据要求

这些单元测试确保了 getFromURL 函数在处理不同输入情况时,能够正确地返回相应的错误或结果。通过这些测试,可以验证函数的Robustness和正确性。需要测试的网络请求状况如下:

DataURLResponseErrorStateResult
nilnilnilinvalid
nilURLResponsenilinvalid
nilHTTPURLResponsenilinvalid
valuenilnilinvalid
valuenilvalueinvalid
nilURLResponsevalueinvalid
nilHTTPURLResponsevalueinvalid
valueURLResponsevalueinvalid
valueHTTPURLResponsevalueinvalid
valueURLResponsenilinvalid
nilHTTPURLResponsenilvalid
nilnilvaluevalid

代码链接

GitHub 仓库

通过这些单元测试,我们可以确保 getFromURL 函数在各种输入情况下的正确性,验证函数的Robustness和可靠性。