Configuring Vapor apps for Testing

Gianluca Tranchedone
The Swift Web Developer

--

When you create a new Vapor application using the command line tools the framework provides, there’s no test target created by default. So, what do you need to do to add tests to your new app?

This guide will help you set up your Vapor project for testing.

TL;DR

I’ve created an alternative template for Vapor already set up for testing. If you’re creating a new project you can use the following command to kick start a project with testing in mind:

vapor new MyApp --template=https://github.com/gtranchedone/vapor-testing-template

N.B. The executable name given by this template is called Executable not App , like the default template! You may need to change some of your deployment configurations. See the notes at the end of this article to see how to update your Heroku configuration.

If you already have a project set up and you want to start writing tests for it, you’ll have to follow the instructions below.

1. Prepare the app for testing

In my last article I’ve discussed how the Swift Package Manager works, and that is fundamental to understanding how to structure your project for testing.

In a nutshell, every subdirectory in the Sources folder is considered to be a target. The same applies to the subdirectories in the Tests folder. Also, any folder containing a main.swift file is considered an executable.

Vapor’s default template creates the following folder structure (I’m omitting some files for the sake of brevity):

.
├── Config
├── Localization
├── Package.swift
├── Public
│ ├── images
│ └── styles
├── README.md
├── Resources
│ └── Views
├── Sources
│ └── App
│ ├── Controllers
│ │ └── PostController.swift
│ ├── Models
│ │ └── Post.swift
│ └── main.swift
└── app.json

Vapor creates an App folder that is an executable. Unfortunately, at the time being XCTest doesn’t support testing executables. Therefore, the first step we have to take is make our App a library so that XCTest can run properly.

Let’s move the main.swift file from Sources/App to a new folder Sources/Executable. You can call this folder whatever you like; it’s not important.

As the entry point to the app now lives in a new module, you’ll need to import the App module to use its classes for routing. Add the following line to main.swift:

import App

Finally, we have to declare that our package now has an Executable target and that it depends on the App module. Update the package manifesto, Package.swift, with the following targets property:

Note that the exclude property should not contain the entry Tests, which was present, until recently, in Vapor’s default template.

The new folder structure now should look like this:

.
├── Config
├── Localization
├── Package.swift
├── Public
│ ├── images
│ └── styles
├── README.md
├── Resources
│ └── Views
├── Sources
│ ├── App
│ │ ├── Controllers
│ │ │ └── PostsController.swift
│ │ └── Models
│ │ └── Post.swift
│ └── Executable
│ └── main.swift
└── app.json

2. Add a test target

Now that the app is properly divided into executable and core app domain, you can add a test target and tests to the project.

To start with, create a Tests directory at the root of your repo. Inside, add a folder called AppTests.

I like to have the same folder structure for both the App and AppTests directories. Therefore, I’ll add both a Controllers and a Models folders into AppTests. Finally, let’s add some tests. Here’s an example:

Now, your app should look like this:

.
├── Config
├── Localization
├── Package.swift
├── Public
│ ├── images
│ └── styles
├── README.md
├── Resources
│ └── Views
├── Sources
│ ├── App
│ │ ├── Controllers
│ │ │ └── PostsController.swift
│ │ └── Models
│ │ └── Post.swift
│ └── Executable
│ └── main.swift
├── Tests
│ └── AppTests
│ ├── Controllers
│ │ └── PostsControllerTests.swift
│ └── Models
│ └── PostTests.swift
└── app.json

3. Fix the tests on Linux

There’s one last problem we have to fix. When running the tests on a Mac, XCTest currently uses the Objective-C runtime to find your tests. However, as there’s no way to do this with Swift, when running the tests on Linux, for example on a CI server, your tests won’t be found, and you’ll get an error.

To fix this issue, you need to add a LinuxMain.swift file inside the Tests directory. As described in the documentation of XCTest, this file needs to explicitly call a function of the framework with the tests you want to run.

The recommended way to handle this is to create a static method in each of your test cases and call it from the LinuxMain.swift file.

With this configuration in place, your tests will run perfectly fine on both macOS and Linux. So, your final application will look like this:

.
├── Config
├── Localization
├── Package.swift
├── Public
│ ├── images
│ └── styles
├── README.md
├── Resources
│ └── Views
├── Sources
│ ├── App
│ │ ├── Controllers
│ │ │ └── PostsController.swift
│ │ └── Models
│ │ └── Post.swift
│ └── Executable
│ └── main.swift
├── Tests
│ ├── AppTests
│ │ ├── Controllers
│ │ │ └── PostsControllerTests.swift
│ │ └── Models
│ │ └── PostTests.swift
│ └── LinuxMain.swift
└── app.json

Notes

This template has an important implication on how your app is executed on the server. In particular you want to make sure that the right executable is being run on the server. By default, Vapor and all tutorials out there assume your executable name is called “App”, however, the executable in our case is called “Executable”.

Updating the Heroku configuration

If you’re using Heroku to deploy your app, edit the Procfile and change the first occurrence of App to Executable. (Note that the following should be all on one line.)

web: Executable --env=production --workdir=./ --config:servers.default.port=$PORT

When you’re setting up Heroku with Vapor using the Vapor Toolbox, you’ll be asked if you want to use a custom executable name. At that point, you should answer ‘yes’ and type ‘Executable’ as the given name. That will make your Procfile right on configuration.

vapor heroku init
...
Do you want to use a custom executable name?
y/n? y
Executable name > Executable
...

Don’t repeat yourself: use a template!

I’ve created a template you can use when creating new Vapor apps using the vapor toolbox, like so:

vapor new MyApp -template=https://github.com/gtranchedone/vapor-testing-template

This will create a project with the folder structure and configuration described in this article, plus an initial test for routes.

Subscribe to Swift Web Weekly!

If you’re interested in web development with Swift, Swift Web Weekly is a free newsletter I’m curating with interesting links related to server-side Swift, HTML, CSS, JavaScript, tools and more. If you don’t like it you can unsubscribe anytime, so why don’t give it a try?! 🙂

--

--

Gianluca Tranchedone
The Swift Web Developer

Software Engineer and Investor. I write about programming and investing.