Swiftpack.co - Package - LiveUI/VaporTestTools

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.

Github

link
Stars: 17
Help us keep the lights on

Dependencies

Releases

0.1.5 - Jun 8, 2018

0.1.4 - Apr 18, 2018

  • Added inline documentation
  • Fixed tests
  • Upgraded dependencies & code

0.1.3 - Mar 26, 2018

0.1.2 - Mar 22, 2018

0.1.1 - Mar 20, 2018

You can now remove services registered by your app to be replaced with mocks