From 69cb762f94d6ace8be1c15fd5bd7e4ef9d234bfd Mon Sep 17 00:00:00 2001 From: Logan Wright Date: Fri, 4 Nov 2016 12:32:13 -0400 Subject: [PATCH 1/2] add basic droplet testing docs --- couscous.yml | 7 ++++ testing/basic.md | 86 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 testing/basic.md diff --git a/couscous.yml b/couscous.yml index 9ac7e3f7..cd1000d2 100644 --- a/couscous.yml +++ b/couscous.yml @@ -150,3 +150,10 @@ menu: websockets-custom: text: Custom relativeUrl: websockets/custom.html + + testing: + name: testing + items: + testing-basic: + text: Basic + relativeUrl: testing/basic.html diff --git a/testing/basic.md b/testing/basic.md new file mode 100644 index 00000000..f08f58ea --- /dev/null +++ b/testing/basic.md @@ -0,0 +1,86 @@ +--- +currentMenu: testing-basic +--- + +# Basic Testing + +Testing is a critical part of any software application, and Vapor apps should be no different. In this documentation, we'll cover some of the basic setup required to be able to test against our `Droplet`. + +## Displacing Droplet Creation Logic + +Up to this point, a lot of our documentation has centered around putting our `Droplet` creation logic in `main.swift`. Unfortunately, when testing against our application, this code becomes largely inaccessible. The first thing we'll need to do is break this out. + +Here's an example of my setup file. I name mine `Droplet+Setup.swift`. Here's how it might look: + +```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. +} +``` + +> [WARNING] Do **not** call `run()` anywhere within the `load` function as this is a blocking call and will create problems later + +## Updated `main.swift` + +Now that we've abstracted our loading logic, we'll need to update our `main.swift` to reflect those changes. Here's how it should look after: + +```swift +let drop = Droplet(... +try load(drop) +drop.run() +``` + +> The reason we still initialize `Droplet` outside of the scope of `load` is so that we can have the option to initialize differently for testing. We'll cover that soon. + +## Testable Droplet + +The first thing I like to do is in my testing target, add a file called `Droplet+Test.swift`. It will look like this: + +```swift +import Vapor + +func makeTestDroplet() throws -> Droplet { + let drop = Droplet(arguments: ["dummy/path/", "prepare"], ... + try load(drop) + try drop.runCommands() + return drop +} +``` + +This looks a lot like our initializer in `main.swift`, but there are 2 very key differences. + +### Droplet(arguments: ["dummy/path/", "prepare"], ... + +The `arguments:` parameter in our `Droplet` creation. This is rarely used except for advanced situations, but we'll use it here in testing to ensure that our `Droplet` doesn't try to automatically `serve` and block our thread. You can use arguments besides `"prepare"`, but unless you're doing something specific for an advanced situation, these arguments should suffice. + +### try drop.runCommands() + +You'll notice here that we're calling `runCommands()` instead of `run()`. This allows the `Droplet` to do all the setup it would normally do before booting without actually binding to a socket or exiting. + +## Test Our Droplet + +Now that all of this has been created, we're ready to start testing our application's `Droplet`. Here's how a really basic test might look: + +```swift +func testEndpoint() throws { + let drop = try makeTestDroplet() + let request = ... + let expectedBody = ... + + let response = try drop.respond(to: request) + XCTAssertEqual(expectedBody, response.body.bytes) +} +``` + +Good luck, and happy testing! From d79c57705a8c414b1dbb879d7330e6cf206dd350 Mon Sep 17 00:00:00 2001 From: Logan Wright Date: Fri, 4 Nov 2016 14:43:14 -0400 Subject: [PATCH 2/2] cleanup comments --- testing/basic.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/testing/basic.md b/testing/basic.md index f08f58ea..1c3a5a3b 100644 --- a/testing/basic.md +++ b/testing/basic.md @@ -29,14 +29,14 @@ func load(_ drop: Droplet) throws { } ``` -> [WARNING] Do **not** call `run()` anywhere within the `load` function as this is a blocking call and will create problems later +> [WARNING] Do **not** call `run()` anywhere within the `load` function as `run()` is a blocking call. ## Updated `main.swift` Now that we've abstracted our loading logic, we'll need to update our `main.swift` to reflect those changes. Here's how it should look after: ```swift -let drop = Droplet(... +let drop = Droplet(...) try load(drop) drop.run() ``` @@ -45,13 +45,13 @@ drop.run() ## Testable Droplet -The first thing I like to do is in my testing target, add a file called `Droplet+Test.swift`. It will look like this: +The first thing we'll do is in my testing target, add a file called `Droplet+Test.swift`. It will look like this: ```swift import Vapor func makeTestDroplet() throws -> Droplet { - let drop = Droplet(arguments: ["dummy/path/", "prepare"], ... + let drop = Droplet(arguments: ["dummy/path/", "prepare"], ...) try load(drop) try drop.runCommands() return drop