测试环节是任何软件应用程序开发的关键部分,而Vapor应用程序也不例外。 在本文档中,我们将介绍一些能够针对Droplet
进行测试的基本设置。
Displacing Droplet Creation Logic
之前我们都是将创建Droplet
的代码放在main.swift
里。不幸的是,在测试的时候,因为代码量很大而使其可读性变得很差。首先我们需要将这些代码分解成AppLogic
模块。
下面是Droplet+Setup.swift
文件:
import Vapor
func load(_ drop: Droplet) throws {
drop.preparations.append(Todo.self)
drop.get { _ in return "put my droplet's logic in this `load` function" }
drop.post("form") { req in
...
return Response(body: "Successfully posted form.")
}
// etc.
}
警告:在
load
函数中不要调用run()
方法。
Update main.swift
上面已经将load的逻辑抽出去了,然后我们需要更新App
模块的main.swift
文件。
let drop = Droplet(...)
try load(drop)
drop.run()
之所以在load之外进行初始化,是为了我们在测试时可以选择不同的初始化方法。
Testable Droplet
首先在测试target中添加一个Droplet+Test.swift
文件。内容如下:
@testable import Vapor
func makeTestDroplet() throws -> Droplet {
let drop = Droplet(arguments: ["dummy/path/", "prepare"], ...)
try load(drop)
try drop.runCommands()
return drop
}
看上去和main.swift
中的初始化方法一样,但是有3点不同。
Droplet(arguments: ["dummy/path/", "prepare"], ...
在Droplet
的创建中,arguments
不同。除了在高级情景中者很少使用,我们在测试时这么使用是为了保证Droplet
不会自动启动服务或者阻塞线程。你可以使用"prepare"
之外的参数,但是除非你是在某些高级场景下执行特殊功能,否则这些参数足够了。
try drop.runCommands()
你可能注意到了,我们使用runCommands()
代替了run()
。这允许Droplet
在启动之前执行正常情况下能够做的所有设置,而不会实际绑定到socket或退出。(<b>这我也不知道该怎么翻译了,待理解后更改</b>)
@testable import Vapor
导入测试的Vapor
确保可以调用runCommands()
方法。目前这个方法未公开,避免在实际使用时出现意外的bug。
Test Our Droplet
现在都已经创建完毕了,可以开始测试我们的Droplet
了。下面是一些基本的测试:
@testable import AppLogic
func testEndpoint() throws {
let drop = try makeTestDroplet()
let request = ...
let expectedBody = ...
let response = try drop.respond(to: request)
XCTAssertEqual(expectedBody, response.body.bytes)
}
请注意,现在你可以使用CMD-U
在Xcode
中运行带有in-line
结果的测试。 此外,您可以运行vapor test
命令测试你的代码。 如果你选择使用swift build
命令,并且你在应用程序中使用了MySQL
,请确保你添加了可调用的正确的构建标识--flag。
祝你好运,愉快的测试吧!(😯)