Add Must & Mustf - #1945
Conversation
brackendawson
left a comment
There was a problem hiding this comment.
Lots of new concepts to testify here.
- Generics
- Assertions gated by go version build constraints
- Assertions which are only in the require package
- It's also debatable that this isn't an assertion, it's a helper function you can use in test setup.
The precedent has been clear in the past that testify does not try to be a utility package. Is it worth breaking all this new ground for what amounts to a 1-line saving.
Also is "must" the best name? By convention it raises errors to a panic, not a test failure.
It's not a no, but these are some points around which I would need some convincing to include the change.
| // The go.mod go directive is go1.17 so that testify keeps building on old | ||
| // toolchains; a //go:build constraint can only raise the language version on | ||
| // Go 1.21 and later, so that is the lowest version this file can be gated on. | ||
| //go:build go1.21 |
There was a problem hiding this comment.
Probably better to gate this on 1.27 too, like in require.Assertions.Must
There was a problem hiding this comment.
Why so, when 1.21 can run the static functions?
There was a problem hiding this comment.
I think it might be confusing to someone using 1.21-1.26 to find that it's available under require but not available under require.Assertions.
I could probably be sold on not changing this part.
There was a problem hiding this comment.
Maybe add it here just for 1.27, and seeing if there’s a demand for static-only usage in prior.
| // | ||
| // Because the test is stopped with [testing.T.FailNow], Must must be called | ||
| // from the goroutine running the test function. | ||
| func Must[T any](t TestingT, f func() (T, error), msgAndArgs ...interface{}) T { |
There was a problem hiding this comment.
Don't mix any and interface{} in the same function declaration.
|
Thank you for your notes. To your concerns:
I would argue that testify already is a utility package, insofar as it wraps testing.T’s primitives with convenience logic like NoError(). In my own experience this 1-line savings repeats over & over, impeding legibility & making tests clunkier. To your points, though: this sort of thing may be more germane to OpenAPI’s fork. |
|
I think we can probably include this. Should we make an assert version too? I'd say no. This is permissible: func TestIfy(t *testing.T) {
b := bytes.Buffer{}
count, err := b.Write(nil)
assert.NoError(t, err)
assert.Equal(t, count, 0)
}But the return parameter is already occupied and almost always ignored so we just can't do it sensibly. I actually never use the assert package myself, only require. I'm also quite supportive of the OpenAPI fork, it's close to the v2 I've always wanted to write. Any major version bump of a Go module is a fork, even if it's made in the same repo, and Stretchr is not the place to go starting a new fork. |
Summary
Convenience methods around operations that must succeed.
Changes
require.Mustandrequire.Mustfgeneric functions.These are usable only in Go 1.21+ and 1.27+, respectively. (The function versions would work in 1.18-1.20, but release-tag limitations in those versions prevent that.)
Motivation
These are convenience methods. Usage looks thus:
It’s a bit more ergonomic than:
Thank you!