Setting Up Integration Testing
Now that we understand both web and authentication components of our application, let's take a look at how we can test the interaction between these two applications. This section will explain:
- Which parts require integration testing,
- How we can implement these integration tests, and
- How we can incorporate these integration tests in our build process.
Explanation of the Tests
As can be seen in the application files, it is the auth.go
file in the web application that contains the code, that interacts with the authentication service. This means that the integration tests must focus on testing the following methods:
- Login (
func (a *authService) Login(username, password string) loginResponse
), - Authenticate (
func (a *authService) Authenticate(username, token string) bool
), and - Logout (
func (a *authService) Logout(username, token string) bool
).
In addition to simply testing these functions, we also need to test a functionality that combines the use of these functions.
The web_test.go
file contains the integration tests that test whether the web application's interaction with the authentication service is as expected. Before we look into the tests in details, we need to set our project up to properly process integration tests.
When we run the go test
command, test functions from all the test files, i.e. files in the current package whose names end with _test.go
, are executed. This is great for unit tests but we might not want this behavior with integration tests for various reasons.
To ensure that integration tests run only when explicitly asked to, we need to tag the relevant test file. Notice line 3 of the web_test.go
file:
// +build integration
This line tags this test file and indicates that go
should pick this file up only when supplied with the integration
tag. In practice, this means that go
will test the functions in this file only when explicitly asked to. This can be done using the following command:
go test -tags integration
Executing this command will test all the test files which are tagged with the integration
keyword.
The web_test.go
file contains the following tests:
- TestWrongUsernamePassword,
- TestCorrectUsernamePassword,
- TestInvalidUserRequestAuthentication,
- TestUserRequestAuthentication, and
- TestUserRequestAuthenticationAfterLoggingOut.
Let's take a look at what each of this test does.
1. TestWrongUsernamePassword
This function expects the authentication service to return a blank token, an indication of failed authentication, when supplied with the wrong username and password.
2. TestCorrectUsernamePassword
This function expects the authentication service to return a valid token, an indication of successful authentication, when supplied with the right username and password.
3. TestInvalidUserRequestAuthentication
This function first performs a login against the authentication service with the wrong username and password. It then tests whether an authentication request using this username and the returned token should fail.
4. TestUserRequestAuthentication
This function first performs a login against the authentication service with the correct username and password. It then tests whether an authentication request using this username and the returned token should succeed.
5. TestUserRequestAuthenticationAfterLoggingOut
This function first performs a login request against the authentication service with the correct username and password. It then uses the returned token to perform a logout request. The function checks that the logout request executes successfully. After a successful logout, the function tries to authenticate against the authentication service using the same username and token. Finally, the function tests that this authentication request fails, which is the expected result as the user has logged out.
Once this is set up, you can run the following command, in the directory of the web application, to perform the integration test:
go test -v -tags integration
If the test finishes without any failures, you should see something similar to the following:
=== RUN TestWrongUsernamePassword
--- PASS: TestWrongUsernamePassword (0.00s)
=== RUN TestCorrectUsernamePassword
--- PASS: TestCorrectUsernamePassword (0.00s)
=== RUN TestInvalidUserRequestAuthentication
--- PASS: TestInvalidUserRequestAuthentication (0.00s)
=== RUN TestUserRequestAuthentication
--- PASS: TestUserRequestAuthentication (0.00s)
=== RUN TestUserRequestAuthenticationAfterLoggingOut
--- PASS: TestUserRequestAuthenticationAfterLoggingOut (0.00s)
PASS
ok _/some_directory_on_your_machine/web-server 0.009s
Note: For all these tests to work, the authentication service should be running. This setup assumes that the authentication service is running on port 8001
. Should that change for you, be sure to update the main.go
and the web_test.go
files in the web application accordingly.
Setting up Semaphore to Automatically Test After a Push
Semaphore makes it trivial to automatically build and test your code as soon as you push it to your repository. Here's how to add your GitHub or Bitbucket project and set up a Golang project on Semaphore.
The default configuration for a Go project takes care of the following:
- Fetching the dependencies,
- Building the project, and
- Running the tests (without any special tags).
Once you've completed this process, you'll be able to see the status of the latest builds and tests on your Semaphore dashboard. After this is done, we need to modify the setup to do the following:
- Set Semaphore to use Docker,
- Run the authentication service in Docker during the build process, and
- Run the integration tests during the build process.
1. Set Semaphore to use Docker
By default, new projects on Semaphore use the Ubuntu 14.04 LTS v1604
platform. This platform doesn't come with Docker. Since we are interested in using Docker, we need to change the platform settings in Semaphore to use the Ubuntu 14.04 LTS v1604 (beta with Docker support)
platform.
2. Run the authentication service in Docker during the build process
After logging in, visit Semaphore's homepage. You should see a list of your projects similar to the following:
On this page, click on the Settings
link highlighted in the above image. This will take you to the settings page of your project.
On this page, click on the Edit Thread
link of the Setup
section highlighted in the image below:
This should make the setup commands editable as follows:
Edit this section to contain the following (we'll soon see what each command does):
go get -t -d -v ./... && go build -v ./...
git clone https://github.com/demo-apps/semaphore-auth-server.git ../auth-server
cd ../auth-server
go get -t -d -v ./... && go build -v -o AuthServer ./...
docker build -t auth-server-image .
docker run -d -p 8001:8001 --name auth-server auth-server-image
cd -
After entering the commands, click on the Save
button to save these commands.
Let's take a look at what each of these commands does.
Command 1 (go get -t -d -v ./... && go build -v ./...
) fetches the application dependencies and builds the project.
Command 2 (git clone https://github.com/demo-apps/semaphore-auth-server.git ../auth-server
) clones the repository containing the source files of the authentication service. These files are put in the auth-server
directory which is located in the parent directory of the main web project.
Command 3 (cd ../auth-server
) changes into the auth-server
directory.
Command 4 (go get -t -d -v ./... && go build -v -o AuthServer ./...
) fetches the dependencies of the authentication service and builds the project. The resulting executable binary is named AuthServer
.
Command 5 (docker build -t auth-server-image .
) builds a Docker image named auth-server-image
based on the Dockerfile
in the auth-server
directory.
Command 6 (docker run -d -p 8001:8001 --name auth-server auth-server-image
) starts a Docker container based on the image created by the previous command. It exposes the application on post 8001
.
Command 7 (cd -
) changes back to the directory containing the files for the web application.
These commands set up the build server so that it has the authentication service up and running in a Docker container. At this point, the integration tests can be executed against this service.
3. Run the integration tests during the build process
On the project settings page, click on the Edit Thread
link of the first thread under the Threads
section, as highlighted below:
This should make the setup commands editable as follows:
Edit this section to contain the following (we'll soon see what each command does):
go test -v ./...
go test -v -tags integration ./...
After entering the commands, to click on the Save
button to save these commands.
Let's take a look at what each of these commands does.
Command 1 (go test -v ./...
) runs the unit tests in the project. While this particular project doesn't have unit tests for the purpose of succinctness, a real project is very likely to have those.
Command 2 (go test -v -tags integration ./...
) runs the integration tests in the project. Specifically, this command runs all the test functions in the test files that have been tagged with the integration
keyword.
After completing this setup, your project will now build and run all the tests automatically, as soon as you push new code into the project repository. Semaphore has a lot of options, that let you customize how and when certain build processes are run. For instance, you can schedule a build process to run at a specific time, or you can manually run the build processes should your project require that.