Migration Guide
Migration Guide from stretchr/testify v1
This guide covers migrating from stretchr/testify to go-openapi/testify/v2.
You can use the automated migration tool or migrate manually.
Automated Migration Tool
migrate-testify automates both the import migration (pass 1) and the generic
upgrade (pass 2). It uses go/packages and go/types for type-checked,
semantics-preserving transformations.
Installation
This installs the migrate-testify binary into your $GOBIN.
Quick Start
Pass 1: Import Migration (--migrate)
Rewrites stretchr/testify imports to go-openapi/testify/v2:
This pass handles:
- Import path rewriting (
assert,require, root package) - Function renames (
EventuallyWithTtoEventuallyWith,NoDirExiststoDirNotExists, etc.) - Type replacement (
PanicTestFunctofunc()) - YAML enable import injection (adds
_ "github.com/go-openapi/testify/v2/enable/yaml"whenYAMLEqis used) - Incompatible import detection (
mock,suite,httppackages emit warnings with guidance) go.modupdate (dropsstretchr/testify, addsgo-openapi/testify/v2)
Pass 2: Generic Upgrade (--upgrade-generics)
Upgrades reflection-based assertions to generic variants where types are statically resolvable and the semantics are preserved:
The tool is conservative: it only upgrades when:
- Argument types are statically known (no
any, nointerface{}) - Types satisfy the required constraint (
comparable,Ordered,Text, etc.) - For
Equal/NotEqual: types are “deeply comparable” (no pointers or structs with pointer fields) - For
Contains: the container type disambiguates toStringContainsT,SliceContainsT, orMapContainsT IsTypeis flagged for manual review (argument count changes)
Assertions that cannot be safely upgraded are tracked and reported in the summary with
a specific reason (e.g., “pointer type”, “interface{}/any”, “type mismatch”).
Use --verbose to see the file and line of each skipped assertion.
Reference
Manual Migration
1. Update Import Paths
2. Optional: Enable YAML Support
If you use YAMLEq assertions: this feature is now opt-in.
Without this import, YAML assertions will panic with a helpful error message.
3. Optional: Enable Colorized Output
Use go additional test flags or environment variables: TESTIFY_COLORIZED=true, TESTIFY_THEME=dark|light
Example:

4. Optional: Adopt Generic Assertions
For better type safety and performance, consider migrating to generic assertion variants. This is entirely optional: reflection-based assertions continue to work as before.
Identify Generic-Capable Assertions
Look for these common assertions in your tests:
Simply add T to the function name. The compiler will check types automatically:
Fix Type Mismatches
The compiler will now catch type errors. This is a featureβit reveals bugs:
Pointer Semantics: When NOT to Upgrade
Generic assertions use Go’s == operator, while reflection-based assertions use reflect.DeepEqual.
For most types these are equivalent, but they differ for pointers and structs containing pointers:
Do not upgrade to generic variants when:
- Arguments are pointer types (
*T) βEqualTcompares addresses, not values - Arguments are structs with pointer fields β
==compares field addresses,DeepEqualcompares field values - You intentionally rely on cross-type comparison (
int64vsint32)
The automated migration tool handles this automatically by only upgrading
assertions where the argument types are “deeply comparable” β types where == and
reflect.DeepEqual produce the same result.
Benefits of Generic Assertions
- Compile-time type safety: Catch errors when writing tests
- Performance: 1.2x to 81x faster (see Benchmarks)
- IDE support: Better autocomplete with type constraints
- Refactoring safety: Type changes break tests at compile time, not runtime
See the Generics Guide for detailed usage patterns and best practices.
5. Remove Suite/Mock Usage
Replace testify mocks with:
- mockery for mocking Replace testify suites with:
- Standard Go subtests for test organization
- or wait until we reintroduce this feature (possible, but not certain)
6. Replace go.uber.org/goleak with NoGoRoutineLeak
If you use go.uber.org/goleak to detect goroutine leaks in tests, consider replacing it
with assert.NoGoRoutineLeak (or require.NoGoRoutineLeak), which is built into testify v2.
This removes the go.uber.org/goleak dependency. This step is not automated by the
migration tool.
7. Remove use of the testify/http package
If you were still using the deprecated package github.com/stretchr/testitfy/http,
you’ll need to replace it by the standard net/http/httptest package.
We won’t reintroduce this package ever.
Breaking Changes Summary
Removed Packages
suite- Use standard Go subtestsmock- Use mockeryhttp- May be reintroduced later
Removed Functions and Types
- All deprecated functions from v1 removed
- Removed extraneous “helper” types:
PanicTestFunc(func())
Behavior Changes
Make sure to check the behavior changes as we have fixed a few quirks in the existing API (mostly edge cases handling).
CollectT.FailNow vs Cancel
In stretchr/testify, CollectT.FailNow() aborts the current tick and lets
EventuallyWithT retry on the next tick. Early versions of this fork changed
that to “cancel the whole assertion immediately”, which effectively broke the
most common pattern (require.X(collect, β¦) inside EventuallyWith).
As of v2.4, CollectT exposes two distinct methods, matching what users
actually want:
| Method | Effect |
|---|---|
collect.FailNow() | Fails the current tick only. Poller retries on the next tick. Matches stretchr. |
collect.Cancel() | Cancels the polling context and aborts the whole assertion immediately. New API. |
Migration from stretchr/testify: no code change is required β FailNow
behaves the same as upstream.
Migration from earlier versions of this fork: if you wrote
collect.FailNow() relying on the whole-assertion-abort behavior, switch the
call to collect.Cancel(). The migration tool emits an advisory warning for
every collect.FailNow() call it finds; review each one and switch to
Cancel() where you want the old behavior. The safe default (keeping
FailNow()) matches the stretchr semantics that most users expect.
Why the split: require-style assertions inside a polling loop are only
useful if they abort the current evaluation and let the loop converge.
Cancelling the whole loop on the first failing tick defeats the purpose of
EventuallyWith. See TRACKING entries for #1819 and
#1830 for the upstream discussions.
See Also
- Changes from v1 - Complete list of all changes, fixes, and new features
- Examples - Practical examples showing v2 usage patterns
- Generics Guide - Learn about the 43 new type-safe generic assertions
- Usage Guide - API conventions and how to navigate the documentation
- Tutorial - Best practices for writing tests with testify v2