单元测试 URL Swift 中的参数

Unit Testing URL Parameters in Swift

我正在尝试使用 TDD 将 URL 单元化为 Swift。我想确保 URL 等于预期的 URL。我正在使用 Router enum,使用 Alamofire 来创建我的 URL。因此,作为 Router enum 的 属性,我有一个 Dictionary<String,String>? 属性,因为我可能不需要其他 URL 的参数。但是,我确实需要用于身份验证的参数 URL.

parametersDictionary<String,String>?如下:

internal enum Router: URLConvertible {

    internal static let baseURLString = "https://xxx.xxxxxx.xxx"

    case authentication(clientID: String)

}

extension Router {

    var pathString: String {
        switch self {
            case .authentication: return "xxxxx/xxxxx/xxxxxxxxx"
        }
    }

    var method: HTTPMethod {
        switch self {
            case .authentication: return .get
        }
    }

    var parameters: Dictionary<String, String>? {
        switch self {
            case .authentication(let clientID): return ["xxxxx": "xxxx", "client_id": clientID]
        }
    }

    func asURL() throws -> URL {
        switch self {
            case .authentication:
               return URL(string: "https://xxx.xxxxxx.xxx/xxxxx/xxxxx/xxxxxxxxx?xxxxx=xxxx&client_id=xxxxxxxxxx")!
        }
    }

}

到目前为止,我已经能够使用 TDD 方式成功编写所有代码。我卡住的地方是测试返回的 URL。由于 parametersDictionary<String,String>? 类型,我想使用以下逻辑迭代 parameters

var parametersStringArray = Array<Dictionary<String,String>>()

for (key, value) in parameters {
    // Create a parameter string from each set
    // Something like the following:
    let parameterString = String(describing: \(key)=\(value))
    parametersStringArray.append(parameterString)
}

let parametersString = parametersStringArray.joined(separator: "&")
let fullURLString = baseURLString + "?\(parametersString)"
return URL(string: fullURLString)!

通过创建这样的参数,当我根据 asURL() throws -> URL 中的 Router enum 返回的 URL 测试预期的 URL 时,它部分时间可能会失败,因为参数是在没有预期顺序的情况下添加到 URL 字符串中的。换句话说,如果我预期的 URL 是 https://xxx.xxxxxx.xxx?xxxxx=xxxx&client_id=xxxxxxxxxx,它可以通过以相反的顺序返回参数来匹配或失败,如下所示:https://xxx.xxxxxx.xxx?client_id=xxxxxxxxxx&xxxxx=xxxx.

对于我测试 URL 是否有更好的解决方案以确保当参数可以按任何顺序返回时返回正确的 URL 因为它们被添加到 URL's string when iterates them?

我是否应该创建两个带有两种参数的 URLs 并匹配任何一种?我认为不合适的原因是因为您拥有的参数越多,您必须创建越多的 URL 来进行测试。

我目前用于测试 URL 身份验证的测试如下:

import XCTest
import Alamofire
@testable import Projects

class AuthenticationURLTests: XCTestCase {

    func test_API_BaseURLString_IsCorrect() {
        let baseURLString = Router.baseURLString
        let expectedBaseURLString = "https://xxx.xxxxxx.xxx/"
        XCTAssertEqual(baseURLString, expectedBaseURLString, "Base URL does not match expected base URL. Expected base URLs to match.")
    }

    func test_API_OAuthPath_IsCorrect() {
        let pathString = Router.authentication(clientID: "xxxxxxxxxx").pathString
        let expectedPathString = "xxxxx/xxxxx/xxxxxxxxx"
        XCTAssertEqual(pathString, expectedPathString, "Path string does not match expected path string. Expected path strings to match.")
    }

    func test_API_OAuthMethod_IsCorrect() {
        let method = Router.authentication(clientID: "xxxxxxxxxx").method
        let expectedMethod = HTTPMethod.get
        XCTAssertEqual(method, expectedMethod, "HTTP methods do not match. Expected HTTP methods to match.")
    }

    func test_API_OAuth_ParametersContainsKeyForXXXXX() {
        let scopeString = Router.authentication(clientID: "xxxxxxxxxx").parameters?["xxxxx"]
        let expectedScopeString = "xxxx"
        XCTAssertEqual(scopeString, expectedScopeString, "Scope strings do not match. Expected scope strings to match.")
    }

    func test_API_OAuth_ParametersContainsKeyForClientID() {
        let clientID = Router.authentication(clientID: "12345abcde").parameters?["client_id"]
        let expectedClientID_Fake = "12345abcde"
        XCTAssertEqual(clientID, expectedClientID_Fake, "Client IDs do not match. Expected client IDs to match.")
    }

    func test_API_OAuth_URLIsCorrect() {
        do {
            let url = try Router.authentication(clientID: "12345abcde").asURL()
            // Here, I want to ensure that the `URL`s match:
            let expectedURL = URL(string: https://xxx.xxxxxx.xxx?xxxxx=xxxx&client_id=xxxxxxxxxx)!
        } catch { XCTFail("Could not create URL for OAuth") }
    }

}

对于所提供代码中的所有 x,我们深表歉意。我想确保我没有提供任何关于我客户申请的信息。

你可以使用 URLComponents.

这个 class 操作 URL 非常方便。例如,它可以是 initialized using a URL instance, and then list all the query parameters in an array via the queryItems property.

Where I am stuck is testing the returned URL.

URLComponents 也符合 Equatable,因此您可以测试返回的 URL 值是否符合您的预期,如下所示:

  1. 创建一个 URLComponents 实例,配置了您期望的所有参数。这是测试的安排部分。
  2. 通过 asURL() 方法获取 URL 的值。这是测试的 act 部分。
  3. 使用刚刚得到的 URL 值创建一个新的 URLComponents 实例,然后将其与使用预期值构建的 URLComponents 进行比较,通过 XCTAssertEqual for例子。这是测试的 assert 部分。

一旦你的所有测试都是绿色的,你可能想查看你的 Router 的实现,看看你是否也可以在其中使用 URLComponents。此 class 由 Apple 提供,非常可靠。