{"id":29117193,"url":"https://github.com/abecodes/dft","last_synced_at":"2025-07-07T08:15:05.571Z","repository":{"id":251508701,"uuid":"837621013","full_name":"abecodes/dft","owner":"abecodes","description":"Docker For Testing is a zero dependency wrapper around the `docker` command.","archived":false,"fork":false,"pushed_at":"2025-01-25T09:17:26.000Z","size":24,"stargazers_count":16,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-29T11:14:17.868Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/abecodes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-03T14:10:31.000Z","updated_at":"2025-03-05T22:55:00.000Z","dependencies_parsed_at":"2025-01-25T10:19:09.953Z","dependency_job_id":"1ea8310c-d57d-48f4-bb24-65d5a65dece4","html_url":"https://github.com/abecodes/dft","commit_stats":null,"previous_names":["abecodes/dft"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/abecodes/dft","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abecodes%2Fdft","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abecodes%2Fdft/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abecodes%2Fdft/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abecodes%2Fdft/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/abecodes","download_url":"https://codeload.github.com/abecodes/dft/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abecodes%2Fdft/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264040974,"owners_count":23548077,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-29T11:14:08.803Z","updated_at":"2025-07-07T08:15:05.554Z","avatar_url":"https://github.com/abecodes.png","language":"Go","readme":"[![Go Report Card](https://goreportcard.com/badge/github.com/abecodes/dft)](https://goreportcard.com/report/github.com/abecodes/dft)  \n[![Go Reference](https://pkg.go.dev/badge/github.com/abecodes/dft.svg)](https://pkg.go.dev/github.com/abecodes/dft)\n\n# 🥼 DFT\n\n**D**ocker **F**or **T**esting is a zero dependency wrapper around the `docker` command. It is solely based on the std lib.\n\nOnly requirement: A running docker daemon.\n\nThe 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.\n\nContainers can be spun up with options for ports, environment variables or [CMD] overwrites.\n\n## 👓 Example\n\nTesting a user service backed by mongoDB\n\n```go\npackage myawesomepkg_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"my/awesome/pkg/repository\"\n\t\"my/awesome/pkg/user\"\n\n\t\"github.com/abecodes/dft\"\n)\n\nfunc TestUserService(tt *testing.T) {\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\n\t// start a mongoDB container\n\tctr, err := dft.StartContainer(\n\t\tctx,\n\t\t\"mongo:7-jammy\",\n\t\tdft.WithRandomPort(27017),\n\t)\n\tif err != nil {\n\t\ttt.Errorf(\"[dft.StartContainer] unexpected error: %v\", err)\n\t\ttt.FailNow()\n\n\t\treturn\n\t}\n\n\t// wait for the database\n\terr = ctr.WaitCmd(\n\t\tctx,\n\t\t[]string{\n\t\t\t\"mongosh\",\n\t\t\t\"--norc\",\n\t\t\t\"--quiet\",\n\t\t\t\"--host=localhost:27017\",\n\t\t\t\"--eval\",\n\t\t\t\"'db.getMongo()'\",\n\t\t},\n\t\tfunc(stdOut string, stdErr string, code int) bool {\n\t\t\ttt.Logf(\"got:\\n\\tcode:%d\\n\\tout:%s\\n\\terr:%s\\n\", code, stdOut, stdErr)\n\n\t\t\treturn code == 0\n\t\t},\n\t\t// since we use a random port in the example we want to execute the\n\t\t// command inside of the container\n\t\tdft.WithExecuteInsideContainer(true),\n\t)\n\tif err != nil {\n\t\ttt.Errorf(\"[dft.WaitCmd] wait error: %v\", err)\n\t\ttt.FailNow()\n\n\t\treturn\n\t}\n\n\t// let's make sure we clean up after us\n\tdefer func() {\n\t\tif ctr != nil {\n\t\t\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\t\t\tctr.Stop(ctx)\n\t\t\tcancel()\n\t\t}\n\t}()\n\n\t// since we use a random port in the example we want to know its\n\t// address on the host. Because we can expose an internal port on multiple host ports,\n\t// this method will return a list of addresses\n\taddrs, ok := ctr.ExposedPortAddresses(27017)\n\tif !ok {\n\t\ttt.Error(\"[ctr.ExposedPortAddresses] did not return any addresses\")\n\t\ttt.FailNow()\n\n\t\treturn\n\t}\n\n\t// get a connection\n\tconn := createNewMongoClient(addrs[0])\n\n\t// create a repo\n\tuserRepo := repository.User(conn)\n\n\t// start the service\n\tuserSvc := user.New(userRepo)\n\tdefer userSvc.Close()\n\n\ttt.Run(\n\t\t\"it can store a new user in the database\",\n\t\tfunc(t *testing.T) {\n\t\t\t// create a new user\n\t\t\tuserSvc.New(\"awesome\", \"user\")\n\n\t\t\t// validate the write via the repository or DB client\n\t\t\tusers := userRepo.GetAll()\n\t\t\tif len(users) != 1 \u0026\u0026\n\t\t\t\tusers[0].FirstName != \"awesome\" \u0026\u0026\n\t\t\t\tusers[0].LastName != \"user\" {\n\t\t\t\t\tt.Error(\"[userSvc.New] unable to create user\")\n\t\t\t\t\ttt.FailNow()\n\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t},\n\t)\n}\n```\n\n## 🤖 API\n\n[Documentation](https://pkg.go.dev/github.com/abecodes/dft)\n\n### StartContainer options\n\n| Option | Info | Example |\n| --- | --- | --- |\n| WithCmd | Overwrite [CMD]. | `WithCmd([]string{\"--tlsCAFile\", \"/run/tls/ca.crt\"})` |\n| WithEnvVar | Set an envvar inside the container.\u003cbr\u003eCan be called multiple times.\u003cbr\u003eIf two options use the same key the latest one will overwrite existing ones. | `WithEnvVar(\"intent\", \"prod\")` |\n| WithMount | Mount a local dir or file\u003cbr\u003eCan be called multiple times. | `WithMount(\"./host/folder\", \"/target\")` |\n| WithPort | Expose an internal port on a specific host port. | `WithPort(27017,8080)` |\n| WithRandomPort | Expose an internal port on a random host port.\u003cbr\u003eUse `ExposedPorts` or `ExposedPortAddresses` to get the correct host port. | `WithRandomPort(27017)` |\n\n### Wait options\n\n| Option | Info | Example |\n| --- | --- | --- |\n| WithExecuteInsideContainer | If the given command should be executed inside of the container (default: false).\u003cbr\u003e This is useful if we want to use a command only present in the container. | `WithExecuteInsideContainer(true)` |\n","funding_links":[],"categories":["Template Engines","Testing","测试"],"sub_categories":["Testing Frameworks"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabecodes%2Fdft","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fabecodes%2Fdft","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabecodes%2Fdft/lists"}