Building the Foundation for End to End Tests

In this lesson, you’ll learn where to put end-to-end tests, and we'll discuss how to build a solid foundation for end-to-end tests, which is very different from unit tests.

Locating end-to-end tests

In Go, unit tests reside in the directory of the package they test. Where should you put end-to-end tests? For a command-line program like multi-git that has a single command called mg in the cmd directory, it makes sense to place the end-to-end tests there:

├── multi-git
│   ├── cmd
│   │   └── mg

However, I think of end-to-end tests as a separate entity that is not embedded with the code it is testing. The whole concept of black-box testing and testing from the outside suggests that testing in different locations is better. Also, in larger systems, there will be many artifacts, services, applications, tools, and commands that require end-to-end tests.

The complete set of end-to-end tests also represent all the meaningful ways to interact with the system. It is convenient for the purposes of learning, documentation, and auditing if all these tests are located in a central location. Finally, it’s quite a mouthful to say “end-to-end tests” again and again. A common shorthand, which we’ll use from now on, is “e2e”. Now, we’ll place all our e2e tests in a top-level directory called e2e_tests:

├── multi-git
│   ├── LICENSE
│   ├──
│   ├── cmd
│   ├── e2e_tests
│   ├── go.mod
│   ├── go.sum
│   └── pkg

Building the foundation for e2e tests

With all the preliminaries out of the way, we can start with a skeleton for end-to-end tests. For multi-git, it’s fine to have a single e2e test. We will use Ginkgo and Gomega for our e2e test just like we did for the unit tests. Here is the directory structure:

├── multi-git
│   ├── e2e_tests
│   │   ├── e2e_suite_test.go
│   │   └── multi_git_test.go

The multi_git_test.go file contains the infrastructure and test cases. In the e2e_tests package, it imports Ginkgo, Gomega, and our very own helpers package as well the os and strings packages from the standard library

package e2e_tests

import (
    . ""
    . ""
    . ""

It also defines a constant for the base directory and a variable for the list of repos.

const baseDir = "/tmp/test-multi-git"

var repoList string

The removeAll() function is identical to the function from the unit tests and removes the base directory completely. It can be argued it should be moved to the helpers package. The BeforeEach function, which is called before every test, calls removeAll() and then rec-creates the base directory from scratch. Therefore, before each test, we start with an empty base directory.

After all the tests finish, the AfterSuite is called once, and the program calls removeAll() to clean up the base directory.

var _ = Describe("multi-git e2e tests", func() {
    var err error

    removeAll := func() {
        err = os.RemoveAll(baseDir)

    BeforeEach(func() {
        err = CreateDir(baseDir, "", false)


Check out the e2e_tests directory and the files it contains in the application below:

Get hands-on with 1200+ tech skills courses.