README
¶
dktest
dktest
is short for dockertest.
dktest
makes it stupidly easy to write integration tests in Go using Docker. Pulling images, starting containers, and cleaning up (even if your tests panic) is handled for you automatically!
API
Run()
is the workhorse
type ContainerInfo struct {
ID string
Name string
ImageName string
IP string
Port string
}
type Options struct {
Timeout time.Duration
ReadyFunc func(ContainerInfo) bool
Env map[string]string
// If you prefer to specify your port bindings as a string, use nat.ParsePortSpecs()
PortBindings nat.PortMap
PortRequired bool
}
func Run(t *testing.T, imgName string, opts Options, testFunc func(*testing.T, ContainerInfo))
Example Usage
import (
"context"
"testing"
)
import (
"github.com/dhui/dktest"
_ "github.com/lib/pq"
)
func pgReady(ctx context.Context, c dktest.ContainerInfo) bool {
ip, port, err := c.FirstPort()
if err != nil {
return false
}
connStr := fmt.Sprintf("host=%s port=%s user=postgres dbname=postgres sslmode=disable", ip, port)
db, err := sql.Open("postgres", connStr)
if err != nil {
return false
}
defer db.Close()
return db.PingContext(ctx) == nil
}
func Test(t *testing.T) {
dktest.Run(t, "postgres:alpine", dktest.Options{PortRequired: true, ReadyFunc: pgReady},
func(t *testing.T, c dktest.ContainerInfo) {
ip, port, err := c.FirstPort()
if err != nil {
t.Fatal(err)
}
connStr := fmt.Sprintf("host=%s port=%s user=postgres dbname=postgres sslmode=disable", ip, port)
db, err := sql.Open("postgres", connStr)
if err != nil {
t.Fatal(err)
}
defer db.Close()
if err := db.Ping(); err != nil {
t.Fatal(err)
}
// Test using db
})
}
For more examples, see the docs.
Debugging tests
Running go test
with the -v
option will display the container lifecycle log statements
along with the container ID.
Short lived tests/containers
Run go test
with the -v
option and specify the LogStdout
and/or LogStderr
Options
to see the container's logs.
Interactive tests/containers
Run go test
with the -v
option to get the container ID and check the container's logs with
docker logs -f $CONTAINER_ID
.
Cleaning up dangling containers
In the unlikely scenario where dktest
leaves dangling containers,
you can find and removing them by using the dktest
label:
# list dangling containers
$ docker ps -a --filter label=dktest
# stop dangling containers
$ docker ps --filter label=dktest | awk '{print $1}' | grep -v CONTAINER | xargs docker stop
# remove dangling containers
$ docker container prune --filter label=dktest
Roadmap
- Support multiple ports in
ContainerInfo
- Use non-default network
- Add more
Options
- Volume mounts
- Network config
- Support testing against multiple containers. It can be faked for now by nested/recursive
Run()
calls but that serializes the containers' startup time.
Comparisons
Last updated: 2020/01/03
dockertest
Why dktest
is better
- Uses the official Docker SDK
- docker/docker (aka moby/moby) uses import path checking, so needs to be imported as
github.com/docker/docker
- docker/docker (aka moby/moby) uses import path checking, so needs to be imported as
- Designed to run in the Go testing environment
- Smaller API surface
- Running Docker containers are automatically cleaned up
- Has better test coverage
- Uses package management (Go modules) properly. e.g. not manually vendored
Why dockertest
is better
- Has been around longer and API is more stable
- More options for configuring Docker containers
- Has more Github stars and contributors
testcontainers-go
TBD
Documentation
¶
Overview ¶
Package dktest provides an easy way to write integration tests using Docker
dktest is short for dockertest
Index ¶
- Variables
- func Run(t *testing.T, imgName string, opts Options, ...)
- func RunContext(ctx context.Context, logger Logger, imgName string, opts Options, ...) (retErr error)
- type ContainerInfo
- func (c ContainerInfo) FirstPort() (hostIP string, hostPort string, err error)
- func (c ContainerInfo) FirstUDPPort() (hostIP string, hostPort string, err error)
- func (c ContainerInfo) Port(containerPort uint16) (hostIP string, hostPort string, err error)
- func (c ContainerInfo) String() string
- func (c ContainerInfo) UDPPort(containerPort uint16) (hostIP string, hostPort string, err error)
- type Logger
- type Options
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // DefaultPullTimeout is the default timeout used when pulling images DefaultPullTimeout = time.Minute // DefaultTimeout is the default timeout used when starting a container and checking if it's ready DefaultTimeout = time.Minute // DefaultReadyTimeout is the default timeout used for each container ready check. // e.g. each invocation of the ReadyFunc DefaultReadyTimeout = 2 * time.Second // DefaultCleanupTimeout is the default timeout used when stopping and removing a container DefaultCleanupTimeout = 15 * time.Second )
Functions ¶
func Run ¶
Run runs the given test function once the specified Docker image is running in a container
func RunContext ¶ added in v0.3.11
func RunContext(ctx context.Context, logger Logger, imgName string, opts Options, testFunc func(ContainerInfo) error) (retErr error)
RunContext is similar to Run, but takes a parent context and returns an error and doesn't rely on a testing.T.
Types ¶
type ContainerInfo ¶
ContainerInfo holds information about a running Docker container
func (ContainerInfo) FirstPort ¶ added in v0.2.0
func (c ContainerInfo) FirstPort() (hostIP string, hostPort string, err error)
FirstPort gets the first published/bound/mapped TCP port. It is always safer to use Port(). This provided as a convenience method and should only be used with Docker images that only expose a single port. If the Docker image exposes multiple ports, then the "first" port will not always be the same.
func (ContainerInfo) FirstUDPPort ¶ added in v0.2.0
func (c ContainerInfo) FirstUDPPort() (hostIP string, hostPort string, err error)
FirstUDPPort gets the first published/bound/mapped UDP port. It is always safer to use UDPPort(). This provided as a convenience method and should only be used with Docker images that only expose a single port. If the Docker image exposes multiple ports, then the "first" port will not always be the same.
func (ContainerInfo) Port ¶
func (c ContainerInfo) Port(containerPort uint16) (hostIP string, hostPort string, err error)
Port gets the specified published/bound/mapped TCP port
func (ContainerInfo) String ¶
func (c ContainerInfo) String() string
String gets the string representation for the ContainerInfo. This is intended for debugging purposes.
type Logger ¶ added in v0.3.11
type Logger interface {
Log(...interface{})
}
Logger is the interface used to log messages.
type Options ¶
type Options struct { // PullTimeout is the timeout used when pulling images PullTimeout time.Duration // Timeout is the timeout used when starting a container and checking if it's ready Timeout time.Duration // ReadyTimeout is the timeout used for each container ready check. // e.g. each invocation of the ReadyFunc ReadyTimeout time.Duration // CleanupTimeout is the timeout used when stopping and removing a container CleanupTimeout time.Duration // CleanupImage specifies whether or not the image should be removed after the test run. // If the image is used by multiple tests, you'll want to cleanup the image yourself. CleanupImage bool ReadyFunc func(context.Context, ContainerInfo) bool Env map[string]string Entrypoint []string Cmd []string // If you prefer to specify your port bindings as a string, use nat.ParsePortSpecs() PortBindings nat.PortMap PortRequired bool LogStdout bool LogStderr bool ShmSize int64 Volumes []string Mounts []mount.Mount Hostname string // Platform specifies the platform of the docker image that is pulled. Platform string ExposedPorts nat.PortSet }
Options contains the configurable options for running tests in the docker image
Source Files
¶
Directories
¶
Path | Synopsis |
---|---|
Package mockdockerclient provides mocks for the Docker client github.com/docker/docker/client
|
Package mockdockerclient provides mocks for the Docker client github.com/docker/docker/client |