@@ -6,18 +6,127 @@ weight: 20
66
77## Migration Guide from stretchr/testify v1
88
9- ### 1. Update Import Path
9+ This guide covers migrating from ` stretchr/testify ` to ` go-openapi/testify/v2 ` .
10+ You can use the [ automated migration tool] ( #automated-migration-tool ) or migrate [ manually] ( #manual-migration ) .
11+
12+ ### Automated Migration Tool
13+
14+ ` migrate-testify ` automates both the import migration (pass 1) and the generic
15+ upgrade (pass 2). It uses ` go/packages ` and ` go/types ` for type-checked,
16+ semantics-preserving transformations.
17+
18+ #### Installation
19+
20+ ``` bash
21+ go install github.com/go-openapi/testify/hack/migrate-testify/v2@latest
22+ ```
23+
24+ This installs the ` migrate-testify ` binary into your ` $GOBIN ` .
25+
26+ #### Quick Start
27+
28+ ``` bash
29+ # Run both passes on the current directory (preview first, then apply)
30+ migrate-testify --all --dry-run .
31+ migrate-testify --all .
32+
33+ # Or run each pass separately
34+ migrate-testify --migrate .
35+ migrate-testify --upgrade-generics .
36+ ```
37+
38+ #### Pass 1: Import Migration (` --migrate ` )
39+
40+ Rewrites ` stretchr/testify ` imports to ` go-openapi/testify/v2 ` :
41+
42+ ``` bash
43+ # Dry-run to preview changes
44+ migrate-testify --migrate --dry-run .
45+
46+ # Apply changes
47+ migrate-testify --migrate .
48+ ```
49+
50+ This pass handles:
51+ - Import path rewriting (` assert ` , ` require ` , root package)
52+ - Function renames (` EventuallyWithT ` to ` EventuallyWith ` , ` NoDirExists ` to ` DirNotExists ` , etc.)
53+ - Type replacement (` PanicTestFunc ` to ` func() ` )
54+ - YAML enable import injection (adds ` _ "github.com/go-openapi/testify/v2/enable/yaml" ` when ` YAMLEq ` is used)
55+ - Incompatible import detection (` mock ` , ` suite ` , ` http ` packages emit warnings with guidance)
56+ - ` go.mod ` update (drops ` stretchr/testify ` , adds ` go-openapi/testify/v2 ` )
57+
58+ #### Pass 2: Generic Upgrade (` --upgrade-generics ` )
59+
60+ Upgrades reflection-based assertions to generic variants where types are statically
61+ resolvable and the semantics are preserved:
62+
63+ ``` bash
64+ # Dry-run to preview changes
65+ migrate-testify --upgrade-generics --dry-run .
66+
67+ # Apply changes
68+ migrate-testify --upgrade-generics .
69+ ```
70+
71+ The tool is conservative: it only upgrades when:
72+ - Argument types are statically known (no ` any ` , no ` interface{} ` )
73+ - Types satisfy the required constraint (` comparable ` , ` Ordered ` , ` Text ` , etc.)
74+ - For ` Equal ` /` NotEqual ` : types are "deeply comparable" (no pointers or structs with pointer fields)
75+ - For ` Contains ` : the container type disambiguates to ` StringContainsT ` , ` SliceContainsT ` , or ` MapContainsT `
76+ - ` IsType ` is flagged for manual review (argument count changes)
77+
78+ Assertions that cannot be safely upgraded are tracked and reported in the summary with
79+ a specific reason (e.g., "pointer type", "interface{}/any", "type mismatch").
80+ Use ` --verbose ` to see the file and line of each skipped assertion.
81+
82+ #### Reference
83+
84+ ```
85+ Usage: migrate-testify [flags] [directory]
86+
87+ Migrate stretchr/testify to go-openapi/testify/v2 and upgrade to generic assertions.
88+
89+ Flags:
90+ -all Run both passes sequentially
91+ -dry-run Show diffs without modifying files
92+ -migrate Run pass 1: stretchr/testify -> go-openapi/testify/v2
93+ -upgrade-generics Run pass 2: reflection -> generic assertions
94+ -verbose Print detailed transformation info
95+ -skip-gomod Skip go.mod changes
96+ -skip-vendor Skip vendor/ directory (default true)
97+ -version string Target testify version (default "v2.3.0")
98+
99+ At least one of --migrate, --upgrade-generics, or --all is required.
100+
101+ Mono-repo support:
102+ Pass 1 walks the filesystem and works across module boundaries.
103+ Pass 2 requires type information and uses go/packages to load code.
104+ For multi-module repos, a go.work file must be present so that pass 2
105+ can load all workspace modules. Create one with:
106+ go work init . ./sub/module1 ./sub/module2 ...
107+
108+ Post-migration checklist:
109+ - Run your linter: the migration may surface pre-existing unchecked linting issues.
110+ - Run your test suite to verify all tests still pass.
111+ ```
112+
113+ ---
114+
115+ ### Manual Migration
116+
117+ #### 1. Update Import Paths
10118
11119``` go
12120// Old
13- ` ` ` go
14- import "github.com/stretchr/testify/v2 "
121+ import " github.com/stretchr/testify/assert "
122+ import " github.com/stretchr/testify/require "
15123
16124// New
17- import "github.com/go-openapi/testify/v2"
125+ import " github.com/go-openapi/testify/v2/assert"
126+ import " github.com/go-openapi/testify/v2/require"
18127```
19128
20- ### 2 . Optional : Enable YAML Support
129+ #### 2. Optional: Enable YAML Support
21130
22131If you use ` YAMLEq ` assertions: this feature is now opt-in.
23132
@@ -27,7 +136,7 @@ import _ "github.com/go-openapi/testify/enable/yaml/v2"
27136
28137Without this import, YAML assertions will panic with a helpful error message.
29138
30- ### 3 . Optional : Enable Colorized Output
139+ #### 3. Optional: Enable Colorized Output
31140
32141``` go
33142import _ " github.com/go-openapi/testify/enable/colors/v2"
@@ -43,11 +152,11 @@ go test -v -testify.colorized -testify.theme=light .
43152
44153![ Colorized Test] ( colorized.png )
45154
46- ### 4. Optional: Adopt Generic Assertions
155+ #### 4. Optional: Adopt Generic Assertions
47156
48157For better type safety and performance, consider migrating to generic assertion variants. This is entirely optional—reflection-based assertions continue to work as before.
49158
50- #### Step 1: Identify Generic-Capable Assertions
159+ ##### Identify Generic-Capable Assertions
51160
52161Look for these common assertions in your tests:
53162
@@ -75,8 +184,6 @@ assert.IsDecreasing → assert.IsDecreasingT
75184assert.IsType (t, User {}, v) → assert.IsOfTypeT [User](t, v) // No dummy value!
76185```
77186
78- #### Step 2: Add Type Suffix
79-
80187Simply add ` T ` to the function name. The compiler will check types automatically:
81188
82189``` go
@@ -89,14 +196,14 @@ assert.EqualT(t, expected, actual)
89196assert.ElementsMatchT (t, slice1, slice2)
90197```
91198
92- #### Step 3: Fix Type Mismatches
199+ ##### Fix Type Mismatches
93200
94201The compiler will now catch type errors. This is a feature—it reveals bugs:
95202
96203``` go
97204// Compiler catches this
98205assert.EqualT (t, int64 (42 ), int32 (42 ))
99- // ❌ Error: mismatched types int64 and int32
206+ // Error: mismatched types int64 and int32
100207
101208// Fix: Use same type
102209assert.EqualT (t, int64 (42 ), int64 (actual))
@@ -105,7 +212,29 @@ assert.EqualT(t, int64(42), int64(actual))
105212assert.Equal (t, int64 (42 ), int32 (42 )) // Still works
106213```
107214
108- #### Benefits of Migration
215+ ##### Pointer Semantics: When NOT to Upgrade
216+
217+ Generic assertions use Go's ` == ` operator, while reflection-based assertions use ` reflect.DeepEqual ` .
218+ For most types these are equivalent, but ** they differ for pointers and structs containing pointers** :
219+
220+ ``` go
221+ a := &MyStruct{Name: " alice" }
222+ b := &MyStruct{Name: " alice" }
223+
224+ assert.Equal (t, a, b) // PASSES (reflect.DeepEqual compares pointed-to values)
225+ assert.EqualT (t, a, b) // FAILS (== compares pointer addresses)
226+ ```
227+
228+ ** Do not upgrade to generic variants when:**
229+ - Arguments are pointer types (` *T ` ) — ` EqualT ` compares addresses, not values
230+ - Arguments are structs with pointer fields — ` == ` compares field addresses, ` DeepEqual ` compares field values
231+ - You intentionally rely on cross-type comparison (` int64 ` vs ` int32 ` )
232+
233+ The automated migration tool handles this automatically by only upgrading
234+ assertions where the argument types are "deeply comparable" — types where ` == ` and
235+ ` reflect.DeepEqual ` produce the same result.
236+
237+ ##### Benefits of Generic Assertions
109238
110239- ** Compile-time type safety** : Catch errors when writing tests
111240- ** Performance** : 1.2x to 81x faster (see [ Benchmarks] ( ../project/maintainers/BENCHMARKS.md ) )
@@ -114,33 +243,62 @@ assert.Equal(t, int64(42), int32(42)) // Still works
114243
115244See the [ Generics Guide] ( ./GENERICS.md ) for detailed usage patterns and best practices.
116245
117- ### 5. Remove Suite/Mock Usage
246+ #### 5. Remove Suite/Mock Usage
118247
119- Replace testify mocks with:
248+ Replace testify mocks with:
120249- [ mockery] ( https://github.com/vektra/mockery ) for mocking
121250Replace testify suites with:
122251- Standard Go subtests for test organization
123252- or wait until we reintroduce this feature (possible, but not certain)
124253
125- ### 6. Remove use of the ` testify/http ` package
254+ #### 6. Replace ` go.uber.org/goleak ` with ` NoGoRoutineLeak `
255+
256+ If you use ` go.uber.org/goleak ` to detect goroutine leaks in tests, consider replacing it
257+ with ` assert.NoGoRoutineLeak ` (or ` require.NoGoRoutineLeak ` ), which is built into testify v2.
258+
259+ ``` go
260+ // Before (with goleak)
261+ import " go.uber.org/goleak"
262+
263+ func TestNoLeak (t *testing .T ) {
264+ defer goleak.VerifyNone (t)
265+ // ... test code ...
266+ }
267+
268+ // After (with testify v2)
269+ import " github.com/go-openapi/testify/v2/assert"
270+
271+ func TestNoLeak (t *testing .T ) {
272+ assert.NoGoRoutineLeak (t, func () {
273+ // ... test code ...
274+ })
275+ }
276+ ```
277+
278+ This removes the ` go.uber.org/goleak ` dependency. This step is not automated by the
279+ migration tool.
280+
281+ #### 7. Remove use of the ` testify/http ` package
126282
127283If you were still using the deprecated package ` github.com/stretchr/testitfy/http ` ,
128284you'll need to replace it by the standard ` net/http/httptest ` package.
129285
130286We won't reintroduce this package ever.
131287
288+ ---
289+
132290## Breaking Changes Summary
133291
134292### Removed Packages
135293
136- - ❌ ` suite ` - Use standard Go subtests
137- - ❌ ` mock ` - Use [ mockery] ( https://github.com/vektra/mockery )
138- - ❌ ` http ` - May be reintroduced later
294+ - ` suite ` - Use standard Go subtests
295+ - ` mock ` - Use [ mockery] ( https://github.com/vektra/mockery )
296+ - ` http ` - May be reintroduced later
139297
140298### Removed Functions and Types
141299
142- - ❌ All deprecated functions from v1 removed
143- - ❌ Removed extraneous "helper" types: ` PanicTestFunc ` (` func() ` )
300+ - All deprecated functions from v1 removed
301+ - Removed extraneous "helper" types: ` PanicTestFunc ` (` func() ` )
144302
145303### Behavior Changes
146304
@@ -156,4 +314,3 @@ Make sure to check the [behavior changes](./CHANGES.md) as we have fixed a few q
156314- [ Generics Guide] ( ./GENERICS.md ) - Learn about the 38 new type-safe generic assertions
157315- [ Usage Guide] ( ./USAGE.md ) - API conventions and how to navigate the documentation
158316- [ Tutorial] ( ./TUTORIAL.md ) - Best practices for writing tests with testify v2
159-
0 commit comments