Make testing Vapor 3 apps easy
Branch: master
Clone or download
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
Other logo Apr 10, 2018
Sources upgrade Jul 24, 2018
Tests
scripts docs plus fixes for the latest release Apr 18, 2018
.gitignore
LICENSE Initial commit Feb 27, 2018
Package.swift add nio and vapor to test targets Nov 20, 2018
README.md Update README.md Apr 18, 2018

README.md

Vapor 3 test tools

Slack Jenkins Platforms Swift Package Manager License Platform

Vaper test tools is (pretty much vhat it says on the tin) a set of methods designed to make testing your endpoints in Vapor 3 a bit more pain-free ...

Slack

Get help using and/or installing this library on the Vapor Slack, and look for @rafiki270

Example

To run the example project on a mac, clone the repo, and run vapor xcode to generate xcode project and run Run target.

Installation

SPM - Swift Package Manager

Import

.package(url: "https://github.com/LiveUI/VaporTestTools.git", from: "0.1.1")

// or to always get the latest changes

.package(url: "https://github.com/LiveUI/VaporTestTools.git", .branch("master"))

Usage

To write tests like this ...

func testHello() {
    let req = HTTPRequest.testable.get(uri: "/hello")
    let res = app.testable.response(to: req).response

    res.testable.debug() // Debug response into the console
    
    let hello = res.testable.content(as: Hello.self)!
    XCTAssertEqual(hello.message, "hello world", "Message is incorrect")

    XCTAssertTrue(res.testable.has(statusCode: .ok), "Wrong status code")
    XCTAssertTrue(res.testable.has(contentType: "text/plain; charset=utf-8"), "Missing content type")
    XCTAssertTrue(res.testable.has(contentLength: 13), "Wrong content length")
    XCTAssertTrue(res.testable.has(content: "Hello, world!"), "Incorrect content")
}

... you first you need to configure your Application object in a test environment. To do that I would recommend creating some form of a helper method that would allow you to access the functionality from any file.

let app = Application.testable.new({ (config, env, services) in
    try! App.configure(&config, &env, &services)
}) { (router) in

}

I would recommend to put the above initialization in a convenience method as described here

And finally create your test file ... the whole thing could look like this:

import XCTest
import Vapor
import VaporTestTools


class GenericControllerTests: XCTestCase {
    
    var app: Application!
    
    // MARK: Linux
    
    static let allTests = [
        ("testHello", testHello),
        ("testPing", testPing),
        ("testNotFound", testNotFound),
        ("testHash", testHash)
    ]

    
    // MARK: Setup
    
    override func setUp() {
        super.setUp()
        
        app = Application.testable.newTestApp()
    }
    
    // MARK: Tests
    
    func testHello() {
        let req = HTTPRequest.testable.get(uri: "/hello")
        let r = app.testable.response(to: req)
        let res = r.response
        
        res.testable.debug()
        
        XCTAssertTrue(res.testable.has(statusCode: .ok), "Wrong status code")
        XCTAssertTrue(res.testable.has(contentType: "text/plain; charset=utf-8"), "Missing content type")
        XCTAssertTrue(res.testable.has(contentLength: 13), "Wrong content length")
        XCTAssertTrue(res.testable.has(content: "Hello, world!"), "Incorrect content")
    }
    
    func testPing() {
        let req = HTTPRequest.testable.get(uri: "/ping")
        let r = app.testable.response(to: req)
        let res = r.response
        
        // Print out info about the Response
        res.testable.debug()
        /*
        Debugging response:
        HTTP [1.1] with status code [200]
        Headers:
            Content-Type = application/json; charset=utf-8
            Content-Length = 15
            Date = Wed, 28 Feb 2018 00:52:02 GMT
        Content:
            Size: 15
            Media type: application/json; charset=utf-8
            Content:
        {"code":"pong"}
        */
        
        XCTAssertTrue(res.testable.has(statusCode: .ok), "Wrong status code")
        XCTAssertTrue(res.testable.has(contentType: "application/json; charset=utf-8"), "Missing content type")
        XCTAssertTrue(res.testable.has(contentLength: 15), "Wrong content length")
        XCTAssertTrue(res.testable.has(content: "{\"code\":\"pong\"}"), "Incorrect content")
    }
    
    func testNotFound() {
        let req = HTTPRequest.testable.get(uri: "/not-found")
        let r = app.testable.response(to: req)
        let res = r.response
        
        res.testable.debug()
        
        XCTAssertTrue(res.testable.has(statusCode: 404), "Wrong status code")
        XCTAssertFalse(res.testable.has(header: "Content-Type"), "Should not content type")
        XCTAssertTrue(res.testable.has(contentLength: 9), "Wrong content length")
        XCTAssertTrue(res.testable.has(content: "Not found"), "Incorrect content")
    }
    
    func testHash() {
        let req = HTTPRequest.testable.get(uri: "/hash/something")
        let r = app.testable.response(to: req)
        let res = r.response
        
        res.testable.debug()
        
        XCTAssertTrue(res.testable.has(statusCode: .ok), "Wrong status code")
        XCTAssertTrue(res.testable.has(contentType: "text/plain; charset=utf-8"), "Missing content type")
        XCTAssertTrue(res.testable.has(contentLength: 60), "Wrong content length")
    }
    
}

To see more examples in action, please see VaporTestTools in action:

Custom Application convenience method

In the following example (Application+Testing.swift) you can see an extension on a testable property which holds all the convenience methods. This will be available through Application.testable.newTestApp()

import Foundation
import App
import Vapor
import VaporTestTools


extension TestableProperty where TestableType: Application {
    
    public static func newTestApp() -> Application {
        let app = new({ (config, env, services) in
            try! App.configure(&config, &env, &services)
        }) { (router) in
            
        }
        return app
    }
    
}

Example Package.swift for testing

Your whole Package.swift file could look something like this:

// swift-tools-version:4.0
import PackageDescription

let package = Package(
    name: "MyApp",
    dependencies: [
        .package(url: "https://github.com/vapor/vapor.git", from: "3.0.0-beta.3.1.3"),
        .package(url: "https://github.com/LiveUI/VaporTestTools.git", from: "0.0.1")
    ],
    targets: [
        .target(
            name: "MyApp",
            dependencies: [
                "Vapor"
            ]
        ),
        .target(name: "Run", dependencies: [
            "MyApp"
            ]),
        .testTarget(name: "AppTests", dependencies: ["TestApp", "VaporTestTools"])
    ]
)

Notice the line .testTarget(name: "AppTests", dependencies: ["TestApp", "VaporTestTools"]) where you create a test target and include VaporTestTools.

Don't forget to star the repo if you think it deserves it! :)

Have fun testing!

Boost - Open source enterprise AppStore

VaporTestTools has been released as a part of a Boost mobile app distribution platform.

More info on http://www.boostappstore.com

Other components in the bundle are:

  • BoostCore - AppStore core module
  • ApiCore - Base user & team management including forgotten passwords, etc ...
  • MailCore - Mailing wrapper for multiple mailing services like MailGun, SendGrig or SMTP (coming)
  • DBCore - Set of tools for work with PostgreSQL database

Author

Ondrej Rafaj (@rafiki270 on Github, Twitter, LiveUI Slack and Vapor Slack)

License

VaporTestTools are available under an MIT license. See the LICENSE file for more info.