testify is fixed at v1, and require will stop your test from a goroutine
A toolkit with common assertions and mocks that plays nicely with the standard library
At a glance
- What is it?
- Four packages, two dependencies, and a note at the top of the README saying that no breaking changes will be accepted in this repository. The assertions are the easy part. The two behaviours that generate real support load are that require must run on the test's own goroutine, and that the suite package does not support parallel tests at all.
- Who is it for?
- testify fits a Go codebase that wants readable assertion failures and readable test code without hand-rolling comparison helpers, and it costs almost nothing to depend on because it pulls two modules. It does not fit a test suite that needs to run in parallel through the suite package, and it will not become a v2 in this repository.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.
Star history
- stretchr/testify26,249 ★ · +30
| Repository | 2026-09-28 | 2026-11-13 |
|---|---|---|
| stretchr/testify | 26.2k | 26.2k |
30 Stars in the last 46 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The first note in the README says v2 is not happening here
Before any feature description, there is a callout. Testify is being maintained at v1, and no breaking changes will be accepted in this repository. The discussion about a v2 is linked, which is where the conversation lives.
For a library this widely depended on, that is the most consequential line in the documentation, and it constrains your planning rather than just describing the present. If your team needs a change that would break an existing signature, this repository is not where it lands. There is no major version to migrate to, no deprecation window, and no upgrade that will force you to revisit call sites.
The release cadence is worth reading against that. v1.11.1 was published on 2025-08-27, then v1.12.0 on 2026-08-17 and v1.12.1 on 2026-08-19. That is a year between a patch release and a feature release, which is consistent with a project that adds carefully and never breaks. The last push was on 2026-11-02 and the repository is not archived, so it is maintained, just conservatively.
The name is a joke that explains the project. The title is Testify, Thou Shalt Write Tests, and the packages are described as tools for testifying that your code will behave as you intend.
Two dependencies and a Go 1.17 floor
The module manifest is the shortest honest summary of what testify costs you. The module requires `github.com/stretchr/objx` at v0.5.3 and `go.yaml.in/yaml/v3` at v3.0.5. Those are the only two direct requirements.
For a test library that most projects pull into every repository, that is a genuinely small surface. You are not adopting a dependency tree, you are adopting two modules, and the second of those is a YAML parser that many projects already have through another route. Note the domain: the YAML module now resolves under `go.yaml.in` rather than the older gopkg.in path, so a project with a stale pin elsewhere may end up with two copies of the same parser in its module graph.
The Go directive is `go 1.17`, and the manifest carries a comment saying it should match the minimum supported version that is tested in the GitHub Actions workflow. So that is not a stale declaration but a deliberate statement of the floor: the oldest toolchain the project tests against. In exchange you get a library that compiles on a very wide range of Go versions, which is a real benefit if you maintain a module that others depend on.
The CI scripts are separate small shell files rather than one workflow file, one each for GitHub Actions, gofmt, code generation and go vet, so each check is independently runnable.
assert returns a bool, require terminates, and the difference is the whole design
The two packages look identical and behave differently in the one way that matters. `require` provides the same global functions as `assert`, but instead of returning a boolean result they terminate the current test.
The `assert` package is the default. Every function takes the `testing.T` object as its first argument, which is how it writes errors out through the normal `go test` capabilities, and every function returns a bool saying whether the assertion passed:
func TestSomething(t *testing.T) {
// assert equality
assert.Equal(t, 123, 123, "they should be equal")
// assert inequality
assert.NotEqual(t, 123, 456, "they should not be equal")
// assert for nil (good for errors)
assert.Nil(t, object)
// assert for not nil (good when you expect something)
if assert.NotNil(t, object) {
// now we know that object isn't nil, we are safe to make
// further assertions without causing any errors
assert.Equal(t, "Something", object.Value)
}
}That `if assert.NotNil(...)` is the pattern to notice. Because the function returns a bool, you can gate further assertions on a precondition, which is how you avoid a cascade of nil dereferences after one failed check. With `require` there is nothing to gate, because the test has already stopped.
The failure mode of getting this backwards is quiet. Use `assert` where you meant `require` and a failed assertion does not stop anything, so every subsequent assertion also runs against invalid state and the report fills with noise. Use `require` where you meant `assert` and you lose a test that would have reported several independent problems at once.
There is a third-party answer to exactly this class of mistake. The README recommends testifylint, run through golangci-lint, to catch common testify errors. If your team adopts the library widely, wiring the linter in is cheaper than reviewing the choice at every call site.
require from a spawned goroutine is a race, not a failure
The `require` package carries a constraint that is stated in the documentation and violated often enough to be worth its own section.
Those functions must be called from the goroutine running the test or benchmark function, not from other goroutines created during the test. Otherwise race conditions may occur. The behaviour being relied on is documented at `t.FailNow`, which is the standard library function that stops a test where it stands.
The reason is structural. Terminating a test is not returning from a function; it is a runtime call that unwinds the test's own goroutine. Call it from a goroutine your test started, and the call has nothing correct to unwind, which is where the race comes from.
So the common shape bites: a test that fans out work across goroutines, collects results, and calls a testify assertion inside each worker. With `assert` that is fine, because it just reports through `testing.T`. With `require` it is a data race, and the symptom under the race detector is a report about your test rather than about the code you were testing. Under normal execution it may appear to work, which is worse.
The rule of thumb that follows: assert inside workers, require on the goroutine that owns the test, and once the workers have reported, assert on the collected result.
The suite package cannot run tests in parallel, and that is a design consequence
The `suite` package carries an explicit warning above its documentation: it does not support parallel tests, with a link to issue 934.
This is not a missing feature someone forgot. The package works by having you build a suite as a struct, embed the suite type, and define setup and teardown methods, and any method whose name begins with Test is run as a test. The embedded type also gives you a `T()` method returning the current testing context. It is a pattern borrowed from more common object-oriented languages, and it gives you a readable, conventional test layout when you would otherwise repeat setup across dozens of functions.
The cost is that the suite owns the test lifecycle. Methods run one after another against shared suite state, and `SetupTest` runs before each. A method that wants to declare itself parallel has no way to express it within that structure, because the state it would share is the suite's. That is why the warning exists rather than a note that parallel support is forthcoming.
The practical consequence is that a large suite is serial by construction, and a codebase that adopted suite early and later wanted `t.Parallel()` across its table-driven cases has to move the parallelism out.
The embedded type also carries the assertion methods, so a suite method can assert without importing the `assert` package separately, which is a small convenience that comes with the pattern.
Mock code is generated, and the generated code is checked in
The `mock` package provides a mechanism for writing mock objects used in place of real ones, and the README's example shows the shape: a struct that embeds `mock.Mock` and implements the interface under test, with each method recording the call and returning whatever the mock is told to return.
type MyMockedObject struct {
mock.Mock
}The workflow is that the test sets up expectations, in the project's own word testify, and then asserts that they happened. Embedding `mock.Mock` is what supplies that machinery, so the hand-written part of a mock is the method bodies, not the expectation recording.
You do not have to write that by hand: the README points to the mockery tool, which autogenerates mock code against an interface.
The repository also has a `_readme-gofmt/` directory and a `.ci.gofmt.sh` script at the top level.
The http package is the one nobody mentions, and the governance is in files
Three packages get the feature list in the README: `assert`, `mock` and `suite`. The repository has a fourth, `http/`, which does not appear in that list.
Its existence is worth noting for a specific reason. HTTP assertions in a test library are a place where helpers can quietly make a test more brittle than the behaviour it checks, and having them inside the library means the comparison rules live in one reviewable place rather than in every codebase's helper file. If you need it, the API documentation on pkg.go.dev is the reference.
Two other directories explain how the project is held together. `internal/` holds code that is deliberately not part of the public API, and `doc.go` and `package_test.go` sit at the root.
Governance is in two plain files. `MAINTAINERS.md` and `EMERITUS.md` record who maintains what and who has stepped back, which for a library this widely depended on is the thing an adopting organisation should read to understand whether the people who wrote a function are still the people who review a change to it.
The overall shape of the dependencies is the point to carry away. Two modules, a wide Go version floor, no breaking changes, and an explicit linter for the mistakes the API design invites. That is a library optimised for not surprising you, which is a different goal from being flexible.
Editorial conclusion
testify fits a Go codebase that wants readable assertion failures and readable test code without hand-rolling comparison helpers, and it costs almost nothing to depend on because it pulls two modules. It does not fit a test suite that needs to run in parallel through the suite package, and it will not become a v2 in this repository. Verify first which of assert or require you reach for in each place, since swapping one for the other changes whether a failure stops execution, and confirm your mocks are not calling require from a spawned goroutine before you trust the result.
Frequently asked questions
how to use testify mock
Define a struct that embeds mock.Mock and implement the interface your code depends on, so each method records the call and returns what the mock is configured to return. In the test, set up expectations and then assert they happened. To skip writing the boilerplate, the README points to the mockery tool, which autogenerates mock code against an interface.
how to use testify
Import the package you need: assert for checks that report and continue, require for checks that stop the test, mock for test doubles, or suite to build a suite as a struct. Every assert function takes the testing.T object as its first argument and returns a bool, and the README recommends running testifylint through golangci-lint to catch common mistakes with the API.
What is the difference between the assert and require packages in testify?
The require package provides the same global functions as assert, but instead of returning a boolean result they terminate the current test. Those functions must be called from the goroutine running the test or benchmark, not from a goroutine the test created, otherwise race conditions may occur.
Is a testify v2 going to happen?
Not in this repository. A note at the top of the README states that testify is being maintained at v1 and that no breaking changes will be accepted here, with a link to the discussion about v2. The last releases were v1.12.0 and v1.12.1 in August 2026, after v1.11.1 in August 2025.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/stretchr-testify)Star history chart for your README
[](https://hysenlabs.com/projects/stretchr-testify)Was this useful?