Skip to content

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.

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.

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.

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.

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 is available on both the test request and response.

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.

// 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.

.running(port: 8123)