Skip to content

Repository files navigation

Go Report Card
Go Reference

🥼 DFT

Docker For Testing is a zero dependency wrapper around the docker command. It is solely based on the std lib.

Only requirement: A running docker daemon.

The package is intended to be used in various testing setups from local testing to CI/CD pipelines. It's main goals are to reduce the need for mocks (especially database ones), and to lower the amount of packages required for testing.

Containers can be spun up with options for ports, environment variables or [CMD] overwrites.

👓 Example

Testing a user service backed by mongoDB

package myawesomepkg_test
import (
"context""testing""time""my/awesome/pkg/repository""my/awesome/pkg/user""github.com/abecodes/dft"
)
funcTestUserService(tt*testing.T) {
ctx, cancel:=context.WithTimeout(context.Background(), 5*time.Second)
defercancel()
// start a mongoDB containerctr, err:=dft.StartContainer(
ctx,
"mongo:7-jammy",
dft.WithRandomPort(27017),
)
iferr!=nil {
tt.Errorf("[dft.StartContainer] unexpected error: %v", err)
tt.FailNow()
return
}
// wait for the databaseerr=ctr.WaitCmd(
ctx,
[]string{
"mongosh",
"--norc",
"--quiet",
"--host=localhost:27017",
"--eval",
"'db.getMongo()'",
},
func(stdOutstring, stdErrstring, codeint) bool {
tt.Logf("got:\n\tcode:%d\n\tout:%s\n\terr:%s\n", code, stdOut, stdErr)
returncode==0
},
// since we use a random port in the example we want to execute the// command inside of the containerdft.WithExecuteInsideContainer(true),
)
iferr!=nil {
tt.Errorf("[dft.WaitCmd] wait error: %v", err)
tt.FailNow()
return
}
// let's make sure we clean up after usdeferfunc() {
ifctr!=nil {
ctx, cancel:=context.WithTimeout(context.Background(), 5*time.Second)
ctr.Stop(ctx)
cancel()
}
}()
// since we use a random port in the example we want to know its// address on the host. Because we can expose an internal port on multiple host ports,// this method will return a list of addressesaddrs, ok:=ctr.ExposedPortAddresses(27017)
if!ok {
tt.Error("[ctr.ExposedPortAddresses] did not return any addresses")
tt.FailNow()
return
}
// get a connectionconn:=createNewMongoClient(addrs[0])
// create a repouserRepo:=repository.User(conn)
// start the serviceuserSvc:=user.New(userRepo)
deferuserSvc.Close()
tt.Run(
"it can store a new user in the database",
func(t*testing.T) {
// create a new useruserSvc.New("awesome", "user")
// validate the write via the repository or DB clientusers:=userRepo.GetAll()
iflen(users) !=1&&users[0].FirstName!="awesome"&&users[0].LastName!="user" {
t.Error("[userSvc.New] unable to create user")
tt.FailNow()
return
}
},
)
}

🤖 API

Documentation

StartContainer options

OptionInfoExample
WithCmdOverwrite [CMD].WithCmd([]string{"--tlsCAFile", "/run/tls/ca.crt"})
WithEnvVarSet an envvar inside the container.
Can be called multiple times.
If two options use the same key the latest one will overwrite existing ones.
WithEnvVar("intent", "prod")
WithMountMount a local dir or file
Can be called multiple times.
WithMount("./host/folder", "/target")
WithPortExpose an internal port on a specific host port.WithPort(27017,8080)
WithRandomPortExpose an internal port on a random host port.
Use ExposedPorts or ExposedPortAddresses to get the correct host port.
WithRandomPort(27017)

Wait options

OptionInfoExample
WithExecuteInsideContainerIf the given command should be executed inside of the container (default: false).
This is useful if we want to use a command only present in the container.
WithExecuteInsideContainer(true)

About

Docker For Testing is a zero dependency wrapper around the `docker` command.

Resources

Stars

19 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages