vapor-docs/build/2.0/testing/basic/index.html

1909 lines
45 KiB
HTML

<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="lang:clipboard.copy" content="Copy to clipboard">
<meta name="lang:clipboard.copied" content="Copied to clipboard">
<meta name="lang:search.language" content="en">
<meta name="lang:search.pipeline.stopwords" content="True">
<meta name="lang:search.pipeline.trimmer" content="True">
<meta name="lang:search.result.none" content="No matching documents">
<meta name="lang:search.result.one" content="1 matching document">
<meta name="lang:search.result.other" content="# matching documents">
<meta name="lang:search.tokenizer" content="[\s\-]+">
<link rel="shortcut icon" href="../../assets/images/favicon.png">
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-3.0.6">
<title>Basic - Vapor Docs</title>
<link rel="stylesheet" href="../../assets/stylesheets/application.451f80e5.css">
<link rel="stylesheet" href="../../assets/stylesheets/application-palette.22915126.css">
<meta name="theme-color" content="#757575">
<script src="../../assets/javascripts/modernizr.1aa3b519.js"></script>
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,700|Roboto+Mono">
<style>body,input{font-family:"Roboto","Helvetica Neue",Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Roboto Mono","Courier New",Courier,monospace}</style>
<link rel="stylesheet" href="../../assets/fonts/material-icons.css">
</head>
<body dir="ltr" data-md-color-primary="grey" data-md-color-accent="grey">
<svg class="md-svg">
<defs>
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448"
viewBox="0 0 416 448" id="__github">
<path fill="currentColor" d="M160 304q0 10-3.125 20.5t-10.75 19-18.125
8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19 18.125-8.5
18.125 8.5 10.75 19 3.125 20.5zM320 304q0 10-3.125 20.5t-10.75
19-18.125 8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19
18.125-8.5 18.125 8.5 10.75 19 3.125 20.5zM360
304q0-30-17.25-51t-46.75-21q-10.25 0-48.75 5.25-17.75 2.75-39.25
2.75t-39.25-2.75q-38-5.25-48.75-5.25-29.5 0-46.75 21t-17.25 51q0 22 8
38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0
37.25-1.75t35-7.375 30.5-15 20.25-25.75 8-38.375zM416 260q0 51.75-15.25
82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5-41.75
1.125q-19.5 0-35.5-0.75t-36.875-3.125-38.125-7.5-34.25-12.875-30.25-20.25-21.5-28.75q-15.5-30.75-15.5-82.75
0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25
30.875q36.75-8.75 77.25-8.75 37 0 70 8 26.25-20.5
46.75-30.25t47.25-9.75q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34
99.5z" />
</svg>
</defs>
</svg>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" data-md-component="overlay" for="__drawer"></label>
<a href="#basic-testing" tabindex="1" class="md-skip">
Skip to content
</a>
<header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid">
<div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink">
<a href="../.." title="Vapor Docs" class="md-header-nav__button md-logo">
<img src="../../images/droplet-white.svg" width="24" height="24">
</a>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__button" for="__drawer"></label>
</div>
<div class="md-flex__cell md-flex__cell--stretch">
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
<span class="md-header-nav__topic">
Vapor Docs
</span>
<span class="md-header-nav__topic">
Basic
</span>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
<label class="md-icon md-search__icon" for="__search"></label>
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
&#xE5CD;
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="result">
<div class="md-search-result__meta">
Type to start searching
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<div class="md-header-nav__source">
<a href="http://github.com/vapor/vapor/" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#__github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
GitHub
</div>
</a>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container">
<main class="md-main">
<div class="md-main__inner md-grid" data-md-component="container">
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" data-md-level="0">
<label class="md-nav__title md-nav__title--site" for="__drawer">
<a href="../.." title="Vapor Docs" class="md-nav__button md-logo">
<img src="../../images/droplet-white.svg" width="48" height="48">
</a>
Vapor Docs
</label>
<div class="md-nav__source">
<a href="http://github.com/vapor/vapor/" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#__github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
GitHub
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../.." title="Overview" class="md-nav__link">
Overview
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-2" type="checkbox" id="nav-2">
<label class="md-nav__link" for="nav-2">
Getting started
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-2">
Getting started
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../getting-started/install-on-macos/" title="Install: macOS" class="md-nav__link">
Install: macOS
</a>
</li>
<li class="md-nav__item">
<a href="../../getting-started/install-on-ubuntu/" title="Install: Ubuntu" class="md-nav__link">
Install: Ubuntu
</a>
</li>
<li class="md-nav__item">
<a href="../../getting-started/toolbox/" title="Toolbox" class="md-nav__link">
Toolbox
</a>
</li>
<li class="md-nav__item">
<a href="../../getting-started/hello-world/" title="Hello, World" class="md-nav__link">
Hello, World
</a>
</li>
<li class="md-nav__item">
<a href="../../getting-started/manual/" title="Manual" class="md-nav__link">
Manual
</a>
</li>
<li class="md-nav__item">
<a href="../../getting-started/xcode/" title="Xcode" class="md-nav__link">
Xcode
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-3" type="checkbox" id="nav-3">
<label class="md-nav__link" for="nav-3">
Vapor
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-3">
Vapor
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../vapor/folder-structure/" title="Folder Structure" class="md-nav__link">
Folder Structure
</a>
</li>
<li class="md-nav__item">
<a href="../../vapor/droplet/" title="Droplet" class="md-nav__link">
Droplet
</a>
</li>
<li class="md-nav__item">
<a href="../../vapor/views/" title="Views" class="md-nav__link">
Views
</a>
</li>
<li class="md-nav__item">
<a href="../../vapor/controllers/" title="Controllers" class="md-nav__link">
Controllers
</a>
</li>
<li class="md-nav__item">
<a href="../../vapor/provider/" title="Provider" class="md-nav__link">
Provider
</a>
</li>
<li class="md-nav__item">
<a href="../../vapor/hash/" title="Hash" class="md-nav__link">
Hash
</a>
</li>
<li class="md-nav__item">
<a href="../../vapor/log/" title="Log" class="md-nav__link">
Log
</a>
</li>
<li class="md-nav__item">
<a href="../../vapor/commands/" title="Commands" class="md-nav__link">
Commands
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-4" type="checkbox" id="nav-4">
<label class="md-nav__link" for="nav-4">
Configs
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-4">
Configs
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../configs/config/" title="Config" class="md-nav__link">
Config
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-5" type="checkbox" id="nav-5">
<label class="md-nav__link" for="nav-5">
JSON
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-5">
JSON
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../json/package/" title="Package" class="md-nav__link">
Package
</a>
</li>
<li class="md-nav__item">
<a href="../../json/overview/" title="Overview" class="md-nav__link">
Overview
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-6" type="checkbox" id="nav-6">
<label class="md-nav__link" for="nav-6">
Routing
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-6">
Routing
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../routing/package/" title="Package" class="md-nav__link">
Package
</a>
</li>
<li class="md-nav__item">
<a href="../../routing/overview/" title="Overview" class="md-nav__link">
Overview
</a>
</li>
<li class="md-nav__item">
<a href="../../routing/parameters/" title="Parameters" class="md-nav__link">
Parameters
</a>
</li>
<li class="md-nav__item">
<a href="../../routing/group/" title="Group" class="md-nav__link">
Group
</a>
</li>
<li class="md-nav__item">
<a href="../../routing/collection/" title="Collection" class="md-nav__link">
Collection
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-7" type="checkbox" id="nav-7">
<label class="md-nav__link" for="nav-7">
Fluent
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-7">
Fluent
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../fluent/package/" title="Package" class="md-nav__link">
Package
</a>
</li>
<li class="md-nav__item">
<a href="../../fluent/getting-started/" title="Getting Started" class="md-nav__link">
Getting Started
</a>
</li>
<li class="md-nav__item">
<a href="../../fluent/model/" title="Model" class="md-nav__link">
Model
</a>
</li>
<li class="md-nav__item">
<a href="../../fluent/database/" title="Database" class="md-nav__link">
Database
</a>
</li>
<li class="md-nav__item">
<a href="../../fluent/query/" title="Query" class="md-nav__link">
Query
</a>
</li>
<li class="md-nav__item">
<a href="../../fluent/relations/" title="Relations" class="md-nav__link">
Relations
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-8" type="checkbox" id="nav-8">
<label class="md-nav__link" for="nav-8">
Cache
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-8">
Cache
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../cache/package/" title="Package" class="md-nav__link">
Package
</a>
</li>
<li class="md-nav__item">
<a href="../../cache/overview/" title="Overview" class="md-nav__link">
Overview
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-9" type="checkbox" id="nav-9">
<label class="md-nav__link" for="nav-9">
MySQL
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-9">
MySQL
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../mysql/package/" title="Package" class="md-nav__link">
Package
</a>
</li>
<li class="md-nav__item">
<a href="../../mysql/provider/" title="Provider" class="md-nav__link">
Provider
</a>
</li>
<li class="md-nav__item">
<a href="../../mysql/driver/" title="Driver" class="md-nav__link">
Driver
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-10" type="checkbox" id="nav-10">
<label class="md-nav__link" for="nav-10">
Redis
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-10">
Redis
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../redis/package/" title="Package" class="md-nav__link">
Package
</a>
</li>
<li class="md-nav__item">
<a href="../../redis/provider/" title="Provider" class="md-nav__link">
Provider
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-11" type="checkbox" id="nav-11">
<label class="md-nav__link" for="nav-11">
Auth
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-11">
Auth
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../auth/package/" title="Package" class="md-nav__link">
Package
</a>
</li>
<li class="md-nav__item">
<a href="../../auth/provider/" title="Provider" class="md-nav__link">
Provider
</a>
</li>
<li class="md-nav__item">
<a href="../../auth/getting-started/" title="Getting Started" class="md-nav__link">
Getting Started
</a>
</li>
<li class="md-nav__item">
<a href="../../auth/helper/" title="Helper" class="md-nav__link">
Helper
</a>
</li>
<li class="md-nav__item">
<a href="../../auth/password/" title="Password" class="md-nav__link">
Password
</a>
</li>
<li class="md-nav__item">
<a href="../../auth/persist/" title="Persist" class="md-nav__link">
Persist
</a>
</li>
<li class="md-nav__item">
<a href="../../auth/redirect-middleware/" title="Redirect Middleware" class="md-nav__link">
Redirect Middleware
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-12" type="checkbox" id="nav-12">
<label class="md-nav__link" for="nav-12">
JWT
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-12">
JWT
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../jwt/package/" title="Package" class="md-nav__link">
Package
</a>
</li>
<li class="md-nav__item">
<a href="../../jwt/overview/" title="Overview" class="md-nav__link">
Overview
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-13" type="checkbox" id="nav-13">
<label class="md-nav__link" for="nav-13">
Sessions
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-13">
Sessions
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../sessions/package/" title="Package" class="md-nav__link">
Package
</a>
</li>
<li class="md-nav__item">
<a href="../../sessions/sessions/" title="Sessions" class="md-nav__link">
Sessions
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-14" type="checkbox" id="nav-14">
<label class="md-nav__link" for="nav-14">
HTTP
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-14">
HTTP
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../http/package/" title="Package" class="md-nav__link">
Package
</a>
</li>
<li class="md-nav__item">
<a href="../../http/request/" title="Request" class="md-nav__link">
Request
</a>
</li>
<li class="md-nav__item">
<a href="../../http/response/" title="Response" class="md-nav__link">
Response
</a>
</li>
<li class="md-nav__item">
<a href="../../http/middleware/" title="Middleware" class="md-nav__link">
Middleware
</a>
</li>
<li class="md-nav__item">
<a href="../../http/body/" title="Body" class="md-nav__link">
Body
</a>
</li>
<li class="md-nav__item">
<a href="../../http/response-representable/" title="ResponseRepresentable" class="md-nav__link">
ResponseRepresentable
</a>
</li>
<li class="md-nav__item">
<a href="../../http/responder/" title="Responder" class="md-nav__link">
Responder
</a>
</li>
<li class="md-nav__item">
<a href="../../http/client/" title="Client" class="md-nav__link">
Client
</a>
</li>
<li class="md-nav__item">
<a href="../../http/server/" title="Server" class="md-nav__link">
Server
</a>
</li>
<li class="md-nav__item">
<a href="../../http/cors/" title="CORS" class="md-nav__link">
CORS
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-15" type="checkbox" id="nav-15">
<label class="md-nav__link" for="nav-15">
Leaf
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-15">
Leaf
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../leaf/package/" title="Package" class="md-nav__link">
Package
</a>
</li>
<li class="md-nav__item">
<a href="../../leaf/provider/" title="Provider" class="md-nav__link">
Provider
</a>
</li>
<li class="md-nav__item">
<a href="../../leaf/leaf/" title="Overview" class="md-nav__link">
Overview
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-16" type="checkbox" id="nav-16">
<label class="md-nav__link" for="nav-16">
Validation (WIP)
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-16">
Validation (WIP)
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../validation/package/" title="Package" class="md-nav__link">
Package
</a>
</li>
<li class="md-nav__item">
<a href="../../validation/overview/" title="Overview" class="md-nav__link">
Overview
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-17" type="checkbox" id="nav-17">
<label class="md-nav__link" for="nav-17">
Node
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-17">
Node
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../node/package/" title="Package" class="md-nav__link">
Package
</a>
</li>
<li class="md-nav__item">
<a href="../../node/getting-started/" title="Getting Started" class="md-nav__link">
Getting Started
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-18" type="checkbox" id="nav-18">
<label class="md-nav__link" for="nav-18">
Core
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-18">
Core
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../core/package/" title="Package" class="md-nav__link">
Package
</a>
</li>
<li class="md-nav__item">
<a href="../../core/overview/" title="Overview" class="md-nav__link">
Overview
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-19" type="checkbox" id="nav-19">
<label class="md-nav__link" for="nav-19">
Bits
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-19">
Bits
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../bits/package/" title="Package" class="md-nav__link">
Package
</a>
</li>
<li class="md-nav__item">
<a href="../../bits/overview/" title="Overview" class="md-nav__link">
Overview
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-20" type="checkbox" id="nav-20">
<label class="md-nav__link" for="nav-20">
Debugging
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-20">
Debugging
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../debugging/package/" title="Package" class="md-nav__link">
Package
</a>
</li>
<li class="md-nav__item">
<a href="../../debugging/overview/" title="Overview" class="md-nav__link">
Overview
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-21" type="checkbox" id="nav-21">
<label class="md-nav__link" for="nav-21">
Deploy
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-21">
Deploy
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../deploy/cloud/" title="Cloud" class="md-nav__link">
Cloud
</a>
</li>
<li class="md-nav__item">
<a href="../../deploy/nginx/" title="Nginx" class="md-nav__link">
Nginx
</a>
</li>
<li class="md-nav__item">
<a href="../../deploy/apache2/" title="Apache2" class="md-nav__link">
Apache2
</a>
</li>
<li class="md-nav__item">
<a href="../../deploy/supervisor/" title="Supervisor" class="md-nav__link">
Supervisor
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-22" type="checkbox" id="nav-22">
<label class="md-nav__link" for="nav-22">
Version (2.0)
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-22">
Version (2.0)
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../version/1_5/" title="1.5" class="md-nav__link">
1.5
</a>
</li>
<li class="md-nav__item">
<a href="../../version/2_0/" title="2.0" class="md-nav__link">
2.0
</a>
</li>
<li class="md-nav__item">
<a href="../../version/3_0/" title="3.0" class="md-nav__link">
3.0
</a>
</li>
<li class="md-nav__item">
<a href="../../version/support/" title="Support" class="md-nav__link">
Support
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="__toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#displacing-droplet-creation-logic" title="Displacing Droplet Creation Logic" class="md-nav__link">
Displacing Droplet Creation Logic
</a>
</li>
<li class="md-nav__item">
<a href="#updated-mainswift" title="Updated main.swift" class="md-nav__link">
Updated main.swift
</a>
</li>
<li class="md-nav__item">
<a href="#testable-droplet" title="Testable Droplet" class="md-nav__link">
Testable Droplet
</a>
<nav class="md-nav">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#dropletarguments-dummypath-prepare" title="Droplet(arguments: ["dummy/path/", "prepare"], ..." class="md-nav__link">
Droplet(arguments: ["dummy/path/", "prepare"], ...
</a>
</li>
<li class="md-nav__item">
<a href="#try-dropruncommands" title="try drop.runCommands()" class="md-nav__link">
try drop.runCommands()
</a>
</li>
<li class="md-nav__item">
<a href="#testable-import-vapor" title="@testable import Vapor" class="md-nav__link">
@testable import Vapor
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#test-our-droplet" title="Test Our Droplet" class="md-nav__link">
Test Our Droplet
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content">
<article class="md-content__inner md-typeset">
<a href="https://github.com/vapor/documentation/edit/master/2.0/docs/testing/basic.md" title="Edit this page" class="md-icon md-content__icon">&#xE3C9;</a>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>This section may contain outdated information.</p>
</div>
<h1 id="basic-testing">Basic Testing<a class="headerlink" href="#basic-testing" title="Permanent link">&para;</a></h1>
<p>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 <code>Droplet</code>.</p>
<h2 id="displacing-droplet-creation-logic">Displacing Droplet Creation Logic<a class="headerlink" href="#displacing-droplet-creation-logic" title="Permanent link">&para;</a></h2>
<p>Up to this point, a lot of our documentation has centered around putting our <code>Droplet</code> creation logic in <code>main.swift</code>. Unfortunately, when testing against our application, this code becomes largely inaccessible. The first thing we'll need to do is break this out into the <code>AppLogic</code> module.</p>
<p>Here's an example of my setup file. I name mine <code>Droplet+Setup.swift</code>. Here's how it might look:</p>
<div class="codehilite"><pre><span></span><span class="kd">import</span> <span class="nc">Vapor</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">load</span><span class="p">(</span><span class="kc">_</span> <span class="n">drop</span><span class="p">:</span> <span class="n">Droplet</span><span class="p">)</span> <span class="kr">throws</span> <span class="p">{</span>
<span class="n">drop</span><span class="p">.</span><span class="n">preparations</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">Todo</span><span class="p">.</span><span class="kc">self</span><span class="p">)</span>
<span class="n">drop</span><span class="p">.</span><span class="kr">get</span> <span class="p">{</span> <span class="kc">_</span> <span class="k">in</span> <span class="k">return</span> <span class="s">&quot;put my droplet&#39;s logic in this `load` function&quot;</span> <span class="p">}</span>
<span class="n">drop</span><span class="p">.</span><span class="n">post</span><span class="p">(</span><span class="s">&quot;form&quot;</span><span class="p">)</span> <span class="p">{</span> <span class="n">req</span> <span class="k">in</span>
<span class="p">...</span>
<span class="k">return</span> <span class="n">Response</span><span class="p">(</span><span class="n">body</span><span class="p">:</span> <span class="s">&quot;Successfully posted form.&quot;</span><span class="p">)</span>
<span class="p">}</span>
<span class="c1">// etc.</span>
<span class="p">}</span>
</pre></div>
<blockquote>
<p>[WARNING] Do <strong>not</strong> call <code>run()</code> anywhere within the <code>load</code> function as <code>run()</code> is a blocking call.</p>
</blockquote>
<h2 id="updated-mainswift">Updated <code>main.swift</code><a class="headerlink" href="#updated-mainswift" title="Permanent link">&para;</a></h2>
<p>Now that we've abstracted our loading logic, we'll need to update our <code>main.swift</code> <strong>in the <code>App</code> module</strong> to reflect those changes. Here's how it should look after:</p>
<div class="codehilite"><pre><span></span><span class="kd">let</span> <span class="nv">drop</span> <span class="p">=</span> <span class="n">Droplet</span><span class="p">(...)</span>
<span class="k">try</span> <span class="n">load</span><span class="p">(</span><span class="n">drop</span><span class="p">)</span>
<span class="n">drop</span><span class="p">.</span><span class="n">run</span><span class="p">()</span>
</pre></div>
<blockquote>
<p>The reason we still initialize <code>Droplet</code> outside of the scope of <code>load</code> is so that we can have the option to initialize differently for testing. We'll cover that soon.</p>
</blockquote>
<h2 id="testable-droplet">Testable Droplet<a class="headerlink" href="#testable-droplet" title="Permanent link">&para;</a></h2>
<p>The first thing we'll do is in my testing target, add a file called <code>Droplet+Test.swift</code>. It will look like this:</p>
<div class="codehilite"><pre><span></span><span class="p">@</span><span class="n">testable</span> <span class="kd">import</span> <span class="nc">Vapor</span>
<span class="kd">func</span> <span class="nf">makeTestDroplet</span><span class="p">()</span> <span class="kr">throws</span> <span class="p">-&gt;</span> <span class="n">Droplet</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nv">drop</span> <span class="p">=</span> <span class="n">Droplet</span><span class="p">(</span><span class="n">arguments</span><span class="p">:</span> <span class="p">[</span><span class="s">&quot;dummy/path/&quot;</span><span class="p">,</span> <span class="s">&quot;prepare&quot;</span><span class="p">],</span> <span class="p">...)</span>
<span class="k">try</span> <span class="n">load</span><span class="p">(</span><span class="n">drop</span><span class="p">)</span>
<span class="k">try</span> <span class="n">drop</span><span class="p">.</span><span class="n">runCommands</span><span class="p">()</span>
<span class="k">return</span> <span class="n">drop</span>
<span class="p">}</span>
</pre></div>
<p>This looks a lot like our initializer in <code>main.swift</code>, but there are 3 very key differences.</p>
<h3 id="dropletarguments-dummypath-prepare">Droplet(arguments: ["dummy/path/", "prepare"], ...<a class="headerlink" href="#dropletarguments-dummypath-prepare" title="Permanent link">&para;</a></h3>
<p>The <code>arguments:</code> parameter in our <code>Droplet</code> creation. This is rarely used except for advanced situations, but we'll use it here in testing to ensure that our <code>Droplet</code> doesn't try to automatically <code>serve</code> and block our thread. You can use arguments besides <code>"prepare"</code>, but unless you're doing something specific for an advanced situation, these arguments should suffice.</p>
<h3 id="try-dropruncommands">try drop.runCommands()<a class="headerlink" href="#try-dropruncommands" title="Permanent link">&para;</a></h3>
<p>You'll notice here that we're calling <code>runCommands()</code> instead of <code>run()</code>. This allows the <code>Droplet</code> to do all the setup it would normally do before booting without actually binding to a socket or exiting.</p>
<h3 id="testable-import-vapor"><code>@testable import Vapor</code><a class="headerlink" href="#testable-import-vapor" title="Permanent link">&para;</a></h3>
<p>We'll need to import the testable compilation of Vapor to access the <code>runCommands</code> function. This is currently not public as a protection against accidental bugs in live apps.</p>
<h2 id="test-our-droplet">Test Our Droplet<a class="headerlink" href="#test-our-droplet" title="Permanent link">&para;</a></h2>
<p>Now that all of this has been created, we're ready to start testing our application's <code>Droplet</code>. Here's how a really basic test might look:</p>
<div class="codehilite"><pre><span></span><span class="p">@</span><span class="n">testable</span> <span class="kd">import</span> <span class="nc">AppLogic</span>
<span class="kd">func</span> <span class="nf">testEndpoint</span><span class="p">()</span> <span class="kr">throws</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nv">drop</span> <span class="p">=</span> <span class="k">try</span> <span class="n">makeTestDroplet</span><span class="p">()</span>
<span class="kd">let</span> <span class="nv">request</span> <span class="p">=</span> <span class="p">...</span>
<span class="kd">let</span> <span class="nv">expectedBody</span> <span class="p">=</span> <span class="p">...</span>
<span class="kd">let</span> <span class="nv">response</span> <span class="p">=</span> <span class="k">try</span> <span class="n">drop</span><span class="p">.</span><span class="n">respond</span><span class="p">(</span><span class="n">to</span><span class="p">:</span> <span class="n">request</span><span class="p">)</span>
<span class="n">XCTAssertEqual</span><span class="p">(</span><span class="n">expectedBody</span><span class="p">,</span> <span class="n">response</span><span class="p">.</span><span class="n">body</span><span class="p">.</span><span class="n">bytes</span><span class="p">)</span>
<span class="p">}</span>
</pre></div>
<p>Notice that now you can use <code>CMD-U</code> to run your tests in Xcode with in-line results. In addition, you can run <code>vapor test</code> to test your code from the command line. If you choose to use <code>swift build</code> instead and you are using MySQL in your app, make sure you add the correct build flags to the call. </p>
<p>Good luck, and happy testing!</p>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Copyright &copy; 2017 Qutheory, LLC
</div>
powered by
<a href="https://www.mkdocs.org">MkDocs</a>
and
<a href="https://squidfunk.github.io/mkdocs-material/">
Material for MkDocs</a>
</div>
<div class="md-footer-social">
<link rel="stylesheet" href="../../assets/fonts/font-awesome.css">
<a href="https://twitter.com/@codevapor" class="md-footer-social__link fa fa-twitter"></a>
<a href="http://vapor.team/" class="md-footer-social__link fa fa-slack"></a>
</div>
</div>
</div>
</footer>
</div>
<script src="../../assets/javascripts/application.5e60981f.js"></script>
<script>app.initialize({version:"1.0.4",url:{base:"../.."}})</script>
<script>!function(e,a,t,n,o,c,i){e.GoogleAnalyticsObject=o,e.ga=e.ga||function(){(e.ga.q=e.ga.q||[]).push(arguments)},e.ga.l=1*new Date,c=a.createElement(t),i=a.getElementsByTagName(t)[0],c.async=1,c.src="https://www.google-analytics.com/analytics.js",i.parentNode.insertBefore(c,i)}(window,document,"script",0,"ga"),ga("create","UA-76177358-4","auto"),ga("set","anonymizeIp",!0),ga("send","pageview");var links=document.getElementsByTagName("a");if(Array.prototype.map.call(links,function(e){e.host!=document.location.host&&e.addEventListener("click",function(){var a=e.getAttribute("data-md-action")||"follow";ga("send","event","outbound",a,e.href)})}),document.forms.search){var query=document.forms.search.query;query.addEventListener("blur",function(){if(this.value){var e=document.location.pathname;ga("send","pageview",e+"?q="+this.value)}})}</script>
</body>
</html>