vapor-docs/docs/advanced/testing.md

100 lines
3.2 KiB
Markdown

# Testing
Vapor includes a module named `XCTVapor` that provides test helpers built on `XCTest`. These testing helpers allow you to send test requests to your Vapor application programmatically or running over an HTTP server.
## Getting Started
To use the `XCTVapor` module, ensure it has been added to your package's test target.
```swift
let package = Package(
...
dependencies: [
.package(url: "https://github.com/vapor/vapor.git", from: "4.0.0")
],
targets: [
...
.testTarget(name: "AppTests", dependencies: [
.target(name: "App"),
.product(name: "XCTVapor", package: "vapor"),
])
]
)
```
Then, add `import XCTVapor` at the top of your test files. Create classes extending `XCTestCase` to write test cases.
```swift
import XCTVapor
final class MyTests: XCTestCase {
func testStub() throws {
// Test here.
}
}
```
Each function beginning with `test` will run automatically when your app is tested.
### Running Tests
Use `cmd+u` with the `-Package` scheme selected to run tests in Xcode. Use `swift test --enable-test-discovery` to test via the CLI.
## Testable Application
Initialize an instance of `Application` using the `.testing` environment. You must call `app.shutdown()` before this application deinitializes.
The shutdown is necessary to help release the resources that the app has claimed. In particular it is important to release the threads the application requests at startup. If you do not call `shutdown()` on the app after each unit test, you may find your test suite crash with a precondition failure when allocating threads for a new instance of `Application`.
```swift
let app = Application(.testing)
defer { app.shutdown() }
try configure(app)
```
Pass the `Application` to your package's `configure(_:)` method to apply your configuration. Any test-only configurations can be applied after.
### Send Request
To send a test request to your application, use the `test` method.
```swift
try app.test(.GET, "hello") { res in
XCTAssertEqual(res.status, .ok)
XCTAssertEqual(res.body.string, "Hello, world!")
}
```
The first two parameters are the HTTP method and URL to request. The trailing closure accepts the HTTP response which you can verify using `XCTAssert` methods.
For more complex requests, you can supply a `beforeRequest` closure to modify headers or encode content. Vapor's [Content API](../basics/content.md) is available on both the test request and response.
```swift
try app.test(.POST, "todos", beforeRequest: { req in
try req.content.encode(["title": "Test"])
}, afterResponse: { res in
XCTAssertEqual(res.status, .created)
let todo = try res.content.decode(Todo.self)
XCTAssertEqual(todo.title, "Test")
})
```
### Testable Method
Vapor's testing API supports sending test requests programmatically and via a live HTTP server. You can specify which method you would like to use by using the `testable` method.
```swift
// Use programmatic testing.
app.testable(method: .inMemory).test(...)
// Run tests through a live HTTP server.
app.testable(method: .running).test(...)
```
The `inMemory` option is used by default.
The `running` option supports passing a specific port to use. By default `8080` is used.
```swift
.running(port: 8123)
```