Testing Vapor Apps with CircleCI

I’ve recently been working on a web app written in Swift. I chose the Vapor framework to accomplish this. When I reached continuous integration, I couldn’t really find much written on the topic. We prefer to use CircleCI, and I’ve set up a few iOS apps on Circle, so I gave it a shot and came up with the following circle.yml that works really well.

This is using version 1.0 of CircleCI. I put some effort into using the 2.0 beta, but found that build times were incredibly slow. I’ll revisit that at some point in the future, because I think using a custom Docker image should make the builds faster.

Machine

This section describes requirements for the build image Circle provides us. In this case, we need Swift 3.1, but Circle’s macOS containers only allow you to select the Xcode version you want. Since Xcode 8.3 comes with Swift 3.1, this gets us the right version of Swift.

Dependencies

Our project requires PostgreSQL, but you can change/remove this requirement depending on your project’s needs. We use Homebrew to install PostgreSQL and Vapor. Next, we call swift package fetch. That uses the Swift Package Manager to fetch your project’s Swift dependencies (found in your Package.swift file). Finally, we cache the .build folder where those dependencies are stored. This drastically speeds up future builds, only downloading new/updated dependencies once.

Compile

The compile step is straightforward. We use vapor build as the framework suggests. It briefly checks that the dependencies are installed (which we downloaded in the previous step) and then builds your app.

Test

At this point, we’ve built our project and just need to run tests! This command is a bit complicated, so I’ll break each piece down.

set -o pipefail

If one command fails, we want the whole command to fail. This is how Circle determines if a build passes or fails. If you leave this part out, you would get false “Passing” results, because the last part of the test command (xcpretty) should never fail.

swift test 2>&1

We run swift test because vapor test suppresses all the useful output. However, swift test prints its output to stderr (instead of stdout). I have no idea why that’s the case, but we use 2>&1 to combine stdout and stderr together.

tee $CIRCLE_ARTIFACTS/test.log

tee takes the output of swift test and both passes it to the next command and writes it to the test.log file. The $CIRCLE_ARTIFACTS folder will save its contents so you can download this output from any test run.

xcpretty –color –report junit –output $CIRCLE_TEST_REPORTS/results.xml

We use xcpretty to convert the output into a junit test report. This is what Circle is expecting. This also prints out a more readable version of the output in the console. $CIRCLE_TEST_REPORTS also saves its contents, so you can download this junit xml file for any test run. Additionally, Circle’s “Test Summary” tab uses this file to show you the results of your tests for that build.

And here is an example of a successful run.

Here is an example of a failure.

Written on May 4, 2017