{"id":13837019,"url":"https://github.com/voicera/tester","last_synced_at":"2025-07-10T16:31:43.668Z","repository":{"id":57495751,"uuid":"83948259","full_name":"voicera/tester","owner":"voicera","description":"Lightweight test utilities to use with Go's testing package","archived":false,"fork":false,"pushed_at":"2019-06-07T03:01:18.000Z","size":61,"stargazers_count":43,"open_issues_count":0,"forks_count":3,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-08-05T15:05:35.847Z","etag":null,"topics":["assertions","data-driven","ddt","go","golang","test-framework","test-hook","test-utilities","tester","testing"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/voicera.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-03-05T05:47:23.000Z","updated_at":"2023-08-20T14:04:00.000Z","dependencies_parsed_at":"2022-08-31T14:24:19.300Z","dependency_job_id":null,"html_url":"https://github.com/voicera/tester","commit_stats":null,"previous_names":["workfit/tester"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voicera%2Ftester","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voicera%2Ftester/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voicera%2Ftester/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voicera%2Ftester/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/voicera","download_url":"https://codeload.github.com/voicera/tester/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225648101,"owners_count":17502172,"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":["assertions","data-driven","ddt","go","golang","test-framework","test-hook","test-utilities","tester","testing"],"created_at":"2024-08-04T15:00:59.382Z","updated_at":"2024-11-20T23:32:08.474Z","avatar_url":"https://github.com/voicera.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# Tester: Test More, Type Less\n\n[![Build Status](https://travis-ci.org/voicera/tester.svg?branch=master)](https://travis-ci.org/voicera/tester)\n[![Go Report Card](https://goreportcard.com/badge/github.com/voicera/tester)](https://goreportcard.com/report/github.com/voicera/tester)\n[![GoDoc](https://godoc.org/github.com/voicera/tester?status.svg)](https://godoc.org/github.com/voicera/tester)\n[![Maintainability](https://api.codeclimate.com/v1/badges/5a77a77b9efb9bacb55d/maintainability)](https://codeclimate.com/github/voicera/tester/maintainability)\n[![Test Coverage](https://api.codeclimate.com/v1/badges/5a77a77b9efb9bacb55d/test_coverage)](https://codeclimate.com/github/voicera/tester/test_coverage)\n\nLightweight test utilities to use with Go's testing package.\n\n## Features\n* Assertions that make tests easier to read, write, and debug\n* Streamlined data providers for data-driven testing (DDT)\n* Test hooks' hygiene check\n\n## Motivations\nTesting is an integral part of Go; the language provides strong and opinionated\nsupport for testing. However, developers who moved from languages like C#, Java,\nand Python miss the convenience of test utilities like assertions and data\nproviders for data-driven tests. That's why we started Tester: lightweight test\nutilities to use with Go's testing package.\n\nMost tests follow the same pattern: set up, invoke the unit under test, assert,\nthen clean up (if need be); said pattern encourages test code reuse\nand consistency. By using test utilities, you can spend more time thinking about\ntest strategies and less time typing boilerplate code.\n\n## Quick Start\nGet the latest version (`go get -u github.com/voicera/tester`) then test away:\n\n```go\npackage hitchhiker\n\nimport (\n    \"testing\"\n\n    \"github.com/voicera/tester/assert\"\n)\n\nfunc TestDeepThought(t *testing.T) {\n    computer := NewDeepThoughtComputer()\n    answer, err := computer.AnswerTheUltimateQuestion()\n    if assert.For(t).ThatActualError(err).IsNil().Passed() {\n        assert.For(t).ThatActual(answer).Equals(42)\n    }\n}\n```\n\n## Learn More\nThe following can also be found at \u003chttps://godoc.org/github.com/voicera/tester\u003e\n\n### Assertions\nPackage `assert` provides a more readable way to assert in test cases;\nfor example:\n\n```go\nassert.For(t).ThatCalling(fn).PanicsReporting(\"expected error\")\n```\n\nThis way, the assert statement reads well; it flows like a proper sentence.\n\nAlso, one can easily tell which value is the test case got (actual)\nand which it wanted (expected); this is key to printing the values correctly\nto make debugging a bit easier. In Go, the actual value is usually printed\nfirst; for example:\n\n```go\nassert.For(t).ThatActual(foo).Equals(expected)\n```\n\nThe above enforces said order in both reading the code and the assertion failure\nmessage (if any).\n\nFor convenience (that also improves readability), there are methods for special\ncases like:\n\n```go\nassert.For(t).ThatActual(foo).IsTrue()\nassert.For(t).ThatActualString(bar).IsEmpty()\n```\n\nWhich are equivalent to:\n\n```go\nassert.For(t).ThatActual(foo).Equals(true)\nassert.For(t).ThatActual(len(bar)).Equals(0)\n```\n\nTo identify a test case in a table-driven test, optional parameters can be\nspecified and will be included in failure messages:\n\n```go\ncases := []struct {\n    id       string\n    actual   interface{}\n    expected interface{}\n}{\n    {\"different values\", 42, 13},\n    {\"different types\", 42.0, 42},\n    {\"different containers\", [...]int{42}, []int{42}},\n}\n\nfor _, c := range cases {\n    assert.For(t, c.id).ThatActual(c.actual).Equals(c.expected)\n}\n```\n\nAfter an assertion is performed, a `ValueAssertionResult` is returned to allow\nfor post-assert actions to be performed; for example:\n\n```go\nassert.For(t).ThatActual(value).Equals(expected).ThenDiffOnFail()\n```\n\nThat will pretty-print a detailed recursive diff of both objects on failure.\n\nIt also can be used as a condition to perform extra test steps:\n\n```go\nvalue := GetValue()\nif assert.For(t).ThatActual(value).IsNotNil().Passed() {\n    assert.For(t).ThatActual(value.GetFoo()).Equals(expected)\n}\n```\n\nOr to perform a deeper analysis of the test values:\n\n```go\nif !assert.For(t).ThatActual(value).Equals(expected).Passed() {\n    analyze(value, expected) // e.g., analyze may look at common bugs\n}\n```\n\nConveniently, the last example above can be rewritten as:\n\n```go\nassert.For(t).ThatActual(value).Equals(expected).ThenRunOnFail(analyze)\n```\n\nAnother use is to print a custom failure message:\n\n```go\nassert.For(t).ThatActual(foo).Equals(bar).ThenRunOnFail(func(actual, expected interface{}) {\n    fmt.Printf(\"JSON: %q != %q\", actual.ToJSON(), expected.ToJSON())\n})\n```\n\nThe above pattern allows for reuse of post-failure analysis and cleanup.\n\nThe interfaces in this package are still a work-in-progress, and are subject\nto change.\n\n### Test Hooks\nWhat exists merely for test code to see shall not be exported to the world.\nYou can tag test-hook fields like the following:\n\n```go\ntype sleeper struct {\n    sleep func(time.Duration) `test-hook:\"verify-unexported\"`\n}\n```\n\nUsing tags, instead of comments, enables you to search the codebase for test\nhooks and validate, via reflection, that they're not exported.\nA test case should be added to verify that test hooks are hidden:\n\n```go\nfunc TestHooksAreHidden(t *testing.T) {\n    assert.For(t).ThatType(reflect.TypeOf(sleeper{})).HidesTestHooks()\n}\n```\n\n### Data-Driven Testing (DDT)\nWhen the number of test cases in a table-driven test gets out of hand and they\ncannot fit neatly in structs anymore, the use of a data provider is in order.\nPackage `ddt` provides a way to load test cases from a JSON file whose path\nis derived from the caller's test function name and file. The file path is\n`\u003cpackage under test\u003e/_ddt/\u003cname of test function\u003e.json`; for example,\n`hitchhiker/_ddt/TestDeepThought.json` with the following schema:\n\n```json\n{\n  \"testCases\": [\n    {\n        \u003cproperties of the test case to unmarshal\u003e\n    },\n    ...\n  ]\n}\n```\n\nFor example, the JSON content may look like the following:\n\n```json\n{\n  \"testCases\": [\n    {\n      \"id\": \"The Ultimate Question\",\n      \"input\": {\n        \"question\": \"What do you get when you multiply six by nine?\",\n        \"timeoutInHours\": 65700000000,\n        \"config\": {\n          \"base\": 13\n        }\n      },\n      \"expected\": {\n        \"answer\": \"42\",\n        \"error\": null\n      }\n    }\n  ]\n}\n```\n\nThe details of the test case struct are left for the tester to specify.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoicera%2Ftester","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvoicera%2Ftester","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoicera%2Ftester/lists"}