I realize I could pass the testing.T
type to the functions that need to deal with the testing interfaces. But how about extending the struct and using it? I know I can type extend but this doesn't work unfortunately:
package test
import "testing"
type testingT testing.T
func (t *testingT) assert(val int) {
if val == 0 {
t.Errorf("%d is zero", val)
}
}
func TestSomething(t *testingT) {
t.assert(0)
}
One solution is embedding as you can see in eduncan911's answer. It's great if you want to add other fields to the new struct.
However, this is not a requirement. Creating a new type having testing.T
as its underlying type (just as you did) is just enough:
type myT testing.T
func (t *myT) assert(val int) {
if val == 0 {
t.Errorf("%d is zero", val)
}
}
In TestSomething()
we can't just call t.assert(0)
because assert()
is not a method of testing.T
but our myT
type. So we need a value of type myT
on which we can call myT.assert()
.
We can't use type assertion to convert a testing.T
to our myT
type though, because type assertion requires the expression to be of interface type! And t
is not an interface type, it's a concrete type: *testing.T
.
The solution is really simple, we can use simple type conversion because myT
and testing.T
has the same underlying type:
my := myT(*t) // Conversion valid, but not yet enough, read on...
The above works, and we can call:
my.assert(0)
But when running tests, it won't fail! Why is that? It's because the above *t
dereferencing, conversion and assignment will make a copy, and my
will be of type myT
but will be a copy of *t
, and so when we call myT.assert()
, it gets a pointer, but a pointer to the copy. And when myT.assert()
calls t.Errorf()
, it will register the error on a copy, so the testing framework will not see this Errorf()
call.
The "final" solution is simple: use type conversion, but don't convert *t
, but t
itself (which is a pointer). Of course *t
cannot be converted to myT
, only to *myT
. And this type needs to be parenthesized (to avoid ambiguity):
func TestSomething(t *testing.T) {
my := (*myT)(t)
my.assert(0)
}
And now we're happy, everything works as expected.
Note: You can also call myT.assert()
in one line if you don't want to call multiple methods of myT
:
func TestSomething(t *testing.T) {
(*myT)(t).assert(0)
}
You can use embedding which would allow you to add your owner methods:
package test
import "testing"
type testingT struct {
*testing.T
}
func (t *testingT) assert(val int) {
if val == 0 {
t.Errorf("%d is zero", val)
}
}
func TestSomething(t *testing.T) {
t2 := &testingT{t}
t2.assert(0)
}