Unit Testing Swift Code on Linux

In this tutorial we will discuss how to write and run unit tests of Swift code in a Linux environment.

What We’ll Cover

We’ll cover creating a basic unit test and using it to test a class. We’ll also discuss some ways
to automate triggering unit tests of a codebase.

I assume the reader has some basic familiarity with the Swift programming language as well as
with tools like make.

Creating the Project

First we’ll start by creating our new project.

First create a directory for your project. I’ll use swiftSVGUnitTesting as my directory. Next cd
into this directory and type

swift package init --type library

This tells Swift Package Manager to create a brand new project of type library. This project will
include target directories for both source code and unit testing. A library is what it sounds like:
A set of code that other folks can pull into their projects and use.

Now open Visual Studio Code and open the swiftSVGUnitTesting directory.

Test Code

Now that we’ve created the project let’s take a look at the automatically generated test code.

Open up the “Tests” folder. In this folder you’ll see two things: A file called LinuxMain.swift, and
a subfolder that contains two files:
swiftSVGUnitTestingTests.swift
XCTestManifests.swift

LinuxMain.swift is simply a driver file that invokes XCTest with all of your unit tests in the
swiftSVGUnitTestingTests directory. As for the actual swiftSVGUnitTestingTests directory itself, the XCTestManifests.swift file is automatically-generated. It builds up the list of all tests to be run in the LinuxMain.swift file.

Let’s open the swiftSVGUnitTestingTests.swift file:

You’ll notice that Swift Package Manager has already created a sample test case. We can use
that to try running the unit tests using SPM.

How to Run Unit Tests

To run your tests you can type swift test from the command line:

Swift Package Manager has built your code and run all of its unit tests.

Writing Some Code

Let’s develop a simple class called the Circle class. This class takes a pair of coordinates and a
radius and can be used to generate the code for a circle svg element.

We’ll write this class and a test to ensure that it creates the correct element.

In your tests directory, under swiftSVGUnitTestingTests, add a new file called CircleTests.swift, then add the following code to it:

import XCTest

import swiftSVGUnitTesting

class CircleTests: XCTestCase {

    func testMakeCircle() {
        let circle = Circle(centerX: 50, centerY: 50, radius: 40)

        let result = circle.render()

        let expectedResult = 
"""
<circle cx="50" cy="50" r="40" />
"""

        XCTAssertEqual(result, expectedResult)

    }
}

As you can see, this test creates an object of type Circle.  It then calls a render() method provided on the Circle class, and validates the resulting code.

As a note, the idea here is that you could develop a number of such classes (rectangle, text, etc) and use them to create a kind of SVG DOM (document object model).  A render method could be provided that would then iterate through that DOM, building out a full SVG document.

Now let’s write the Circle class itself.  In the Sources directory for your project, under swiftSVGUnitTesting, add a file called Circle.swift and add the following code to it to define the Circle type:

public class Circle {

    private let centerX: Int
    private let centerY: Int
    private let radius: Int
    
    public init(centerX: Int, centerY: Int, radius: Int) {
        self.centerX = centerX
        self.centerY = centerY
        self.radius = radius
    }
    
    public func render() -> String {
        return "<circle cx=\"\(centerX)\" cy=\"\(centerY)\" r=\"\(radius)\" />"
    }
}

As you can see, a Circle is just a set of coordinates with a render method that produces a very basic SVG element.  Your CircleTest is designed to validate this behaviour.

Testing Your Code

As we discussed earlier, Swift Package Manager comes with a test command.  This command also lets you build the LinuxMain and its accompanying XCTestManifests.swift file.  This comes in handy as otherwise you’d need to manually add to XCTestManifests each time you created a new test case.

To automatically generate the test manifest type

swift test --enable-test-discovery --generate-linuxmain

Do not worry if the command spits out a warning about being unable to discover tests on linux.  The command will still build the test manifest file and exit.

Now, if you open up the XCTestManifests.swift file you’ll see that our CircleTests have been added to the tests to be run:

Now you can run your tests by typing swift test again:

You’ll notice that now the output includes the result of running the CircleTests.

What about CI/CD?

Let’s go through a strategy to automate this process using the make command.

Start by creating a Makefile in your project directory:

Now let’s add some tasks

.PHONY: setupLinux testLinux

setupLinux:
	swift test --enable-test-discovery --generate-linuxmain

testLinux: setupLinux
	swift test

The makefile above will run the commands we have already discussed.  I’ve broken the test generation down to its own task (setupLinux) in case we ever wished to re-use it in other tasks in the future.

Now you can simply type make testLinux to both rebuild the list of tests to be run and also to run all the tests.

Conclusion

In this tutorial we’ve covered how to write unit tests for your code in a Linux environment.  We’ve also discussed how to add some automation to the process using the make command.

In our next tutorial we’ll cover publishing your swift package so that others can use it.  We’ll also discuss how you can use Github’s Actions feature to automate testing your packages.

See you then.

0 Shares:
Leave a Reply

Your email address will not be published. Required fields are marked *

You May Also Like