更新测试用例

UsesTests

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func testUserCanBeSavedWithAPI() throws {

let user = User(name: usersName, username: usersUsername, password: "password")
...
}

func testUsersCanBeRetrievedFromAPI() throws {
    ...
    // 发请求并获得响应
    let users = try app.getResponse(to: usersURI, decodeTo: [User.Public].self)
    ...
}

Models+testable

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
...
import Crypto
extension User {
    static func create(
        name: String = "Luke",
        username: String? = nil,
        on connection: PostgreSQLConnection) throws -> User {
        var createUsername: String
        if let suppliedUsername = username {
            createUsername = suppliedUsername
        } else {
            createUsername = UUID().uuidString
        }
        let password = try BCrypt.hash("password")

        let user = User(name: name, username: createUsername, password: password)
        return try user.save(on: connection).wait()
    }
}
...

修改后重置docker测试数据库:

1
2
3
4
5
$ docker stop postgres-test
$ docker rm postgres-test
$ docker run --name postgres-test -e POSTGRES_DB=vapor-test \
  -e POSTGRES_USER=vapor -e POSTGRES_PASSWORD=password \
  -p 5433:5432 -d postgres

现在运行测试会产生崩溃,因为对那些需要认证的API的调用会失败:

update-tests-crash-when-run

Application+testable.swift

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
...
import Authentication
extension Application {
    ...
    func sendRequest<T>(
        to path: String,
        method: HTTPMethod,
        headers: HTTPHeaders = .init(),
        body: T? = nil,
        loggedInRequest: Bool = false,
        loggedInUser: User? = nil
        ) throws -> Response where T: Content {

        var headers = headers
        if loggedInRequest || loggedInUser != nil {
            let username: String
            if let user = loggedInUser {
                username = user.username
            } else {
                username = "admin"
            }
            let credentials = BasicAuthorization(username: username, password: "password")

            var tokenHeaders = HTTPHeaders()
            tokenHeaders.basicAuthorization = credentials

            let tokenResponse = try self.sendRequest(to: "/api/users/login", method: .POST, headers:  tokenHeaders)

            let token = try tokenResponse.content.syncDecode(Token.self)
            headers.add(name: .authorization, value: "Bearer \(token.token)")
        }

        // 创建一个和发送到app的HTTP请求
        let request = HTTPRequest(method: method,
                                  url: URL(string: path)!,
                                  headers: headers)
        let wrappedRequest = Request(http: request, using: self)

        if let body = body {
            try wrappedRequest.content.encode(body)
        }

        // 因为app本身没有正式运行,所以这里手动进行j响应
        let responder = try self.make(Responder.self)
        return try responder.respond(to: wrappedRequest).wait()
    }

    func sendRequest(
        to path: String,
        method: HTTPMethod,
        headers: HTTPHeaders = .init(),
        loggedInRequest: Bool = false,
        loggedInUser: User? = nil
    ) throws -> Response {
        let emptyContent: EmptyContent? = nil
        return try sendRequest(to: path,
                               method: method,
                               headers: headers,
                               body: emptyContent,
                               loggedInRequest:loggedInRequest,
                               loggedInUser: loggedInUser)
    }

    func sendRequest<T>(
        to path: String,
        method: HTTPMethod,
        headers: HTTPHeaders,
        data: T,
        loggedInRequest: Bool = false,
        loggedInUser: User? = nil
        ) throws where T: Content {

        _ =  try sendRequest(to: path,
                               method: method,
                               headers: headers,
                               body: data,
                               loggedInRequest: loggedInRequest,
                               loggedInUser: loggedInUser)
    }


    func getResponse<C, T>(
        to path: String,
        method: HTTPMethod = .GET,
        headers: HTTPHeaders = .init(),
        data: C? = nil,
        decodeTo type: T.Type,
        loggedInRequest: Bool = false,
        loggedInUser: User? = nil
        ) throws -> T where C: Content, T: Decodable {

        let response = try self.sendRequest(to: path,
                                            method: method,
                                            headers: headers,
                                            body: data,
                                            loggedInRequest: loggedInRequest,
                                            loggedInUser: loggedInUser)
        // 从响应数据中解析出用户数据,也即从数据库中检索出来的用户数据
        return try response.content.decode(type).wait()
    }

    func getResponse<T> (
        to path: String,
        method: HTTPMethod = .GET,
        headers: HTTPHeaders = .init(),
        decodeTo type: T.Type,
        loggedInRequest: Bool = false,
        loggedInUser: User? = nil
    ) throws -> T where T: Decodable {
        let emptyContent: EmptyContent? = nil
        return try self.getResponse(to: path,
                                    method: method,
                                    headers: headers,
                                    data: emptyContent,
                                    decodeTo: type,
                                    loggedInRequest: loggedInRequest,
                                    loggedInUser: loggedInUser)
    }
}

AcronymTests.swift

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
func testAcronymCanBeSavedWithAPI() throws {
    ...
    let receivedAcronym = try app.getResponse(to: acronymsURI, method: .POST, headers: ["Content-Type": "application/json"], data: acronym, decodeTo: Acronym.self, loggedInRequest: true)
    ...
}

func testUpdatingAnAcronym() throws {
    ...
    try app.sendRequest(to: "\(acronymsURI)\(acronym.id!)", method: .PUT, headers: ["Content-Type": "application/json"], data: updatedAcronym, loggedInUser: newUser)
    ...
}

func testDeletingAnAcronym() throws {
    ...
    _ = try app.sendRequest(to: "\(acronymsURI)\(acronym.id!)", method: .DELETE, loggedInRequest: true)
    ...
}

func testGettingAnAcronymsUser() throws {
    ...
    let acronymsUser = try app.getResponse(to: "\(acronymsURI)\(acronym.id!)/user", decodeTo: User.Public.self)
    ...
}

func testAcronymsCategories() throws {
    ...
    let categories = try app.getResponse(to: "\(acronymsURI)\(acronym.id!)/categories", decodeTo: [App.Category].self, loggedInRequest: true)

    ...

    _ = try app.sendRequest(to: "\(acronymsURI)\(acronym.id!)/categories/\(category.id!)", method: .DELETE)
    let newCategories = try app.getResponse(to: "\(acronymsURI)\(acronym.id!)/categories", decodeTo: [App.Category].self, loggedInRequest: true)

    ...
}

func testAcronymsCategories() throws {
    ...
    let request1URL = "\(acronymsURI)\(acronym.id!)/categories/\(category.id!)"
    _ = try app.sendRequest(to: request1URL,method: .POST,loggedInRequest: true)

    let request2URL = "\(acronymsURI)\(acronym.id!)/categories/\(category2.id!)"
    _ = try app.sendRequest(to: request2URL,method: .POST,loggedInRequest: true)

    let categories = try app.getResponse(to: "\(acronymsURI)\(acronym.id!)/categories", decodeTo: [App.Category].self)

    XCTAssertEqual(categories.count, 2)
    XCTAssertEqual(categories[0].id, category.id)
    XCTAssertEqual(categories[0].name, category.name)
    XCTAssertEqual(categories[1].id, category2.id)
    XCTAssertEqual(categories[1].name, category2.name)

    let request3URL = "\(acronymsURI)\(acronym.id!)/categories/\(category.id!)"
    _ = try app.sendRequest(to: request3URL,method: .DELETE,loggedInRequest: true)
    ...
}

CategoryTests

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
func testCategoryCanBeSavedWithAPI() throws {
    ...
    let receivedCategory = try app.getResponse(to: categoriesURI, method: .POST, headers: ["Content-Type": "application/json"], data: category, decodeTo: Category.self, loggedInRequest:true)
    ...
}

func testGettingACategoriesAcronymsFromTheAPI() throws {
    ...
    let acronym1URL = "/api/acronyms/\(acronym.id!)/categories/\(category.id!)"
    _ = try app.sendRequest(to: acronym1URL, method: .POST,loggedInRequest:true)

    let acronym2URL = "/api/acronyms/\(acronym2.id!)/categories/\(category.id!)"
    _ = try app.sendRequest(to: acronym2URL, method: .POST, loggedInRequest: true)

    let acronyms = try app.getResponse(to: "\(categoriesURI)\(category.id!)/acronyms", decodeTo: [Acronym].self, loggedInRequest: true
    ...
}

UsesTests

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
func testUsersCanBeRetrievedFromAPI() throws {
    ...
    // 发请求并获得响应
    let users = try app.getResponse(to: usersURI, decodeTo: [User.Public].self)
    ...
    // 考虑到有一个管理员帐户
    XCTAssertEqual(users.count, 3)
    XCTAssertEqual(users[1].name, usersName)
    XCTAssertEqual(users[1].username, usersUsername)
    XCTAssertEqual(users[1].id, user.id)
}

func testUserCanBeSavedWithAPI() throws {
    let user = User(name: usersName, username: usersUsername, password: "password")
    let receivedUser = try app.getResponse(to: usersURI,
                                            method: .POST,
                                            headers: ["Content-Type":"application/json"],
                                            data: user,
                                            decodeTo: User.Public.self,
                                            loggedInRequest: true)
    ...
    let users = try app.getResponse(to: usersURI,
                                decodeTo: [User.Public].self)
    ...
    // 考虑到有一个管理员帐户
    XCTAssertEqual(users.count, 2)
    XCTAssertEqual(users[1].name, usersName)
    XCTAssertEqual(users[1].username, usersUsername)
    XCTAssertEqual(users[1].id, receivedUser.id)
}

func testGettingASingleUserFromTheAPI() throws {
    ...
    let receivedUser = try app.getResponse(to: "\(usersURI)\(user.id!)", decodeTo: User.Public.self)
    ...
}

修改完在后一定要跑完单元测试:

update-test-cases-successfully