为了账号安全,请及时绑定邮箱和手机立即绑定

扩展现有的类型 testing.T 以添加额外的检查

扩展现有的类型 testing.T 以添加额外的检查

Go
牧羊人nacy 2022-01-04 14:07:41
我意识到我可以将testing.T类型传递给需要处理测试接口的函数。但是如何扩展结构并使用它呢?我知道我可以输入扩展,但不幸的是这不起作用:package testimport "testing"type testingT testing.Tfunc (t *testingT) assert(val int) {    if val == 0 {        t.Errorf("%d is zero", val)    }}func TestSomething(t *testingT) {    t.assert(0)}
查看完整描述

2 回答

?
狐的传说

TA贡献1804条经验 获得超3个赞

正如您在 eduncan911 的回答中所见,一种解决方案是嵌入。如果您想将其他字段添加到新结构中,那就太好了。


但是,这不是必需的。创建一个新类型testing.T作为其底层类型(就像你所做的那样)就足够了:


type myT testing.T


func (t *myT) assert(val int) {

    if val == 0 {

        t.Errorf("%d is zero", val)

    }

}

使用它

在TestSomething()我们不能只是调用t.assert(0)因为assert()不是方法testing.T而是我们的myT类型。所以我们需要一个myT可以调用的类型值myT.assert()。


我们不能使用类型断言将 a 转换testing.T为我们的myT类型,因为类型断言要求表达式为接口类型!并且t不是接口类型,而是具体类型:*testing.T.


解决方案非常简单,我们可以使用简单的类型转换,因为myT和testing.T具有相同的底层类型:


my := myT(*t)   // Conversion valid, but not yet enough, read on...

以上工作,我们可以调用:


my.assert(0)

但是在运行测试时,它不会失败!这是为什么?这是因为上面的*t解引用、转换和赋值会产生一个副本,并且my是类型myT但是会是的副本*t,所以当我们调用时myT.assert(),它得到一个指针,但是一个指向副本的指针。当myT.assert()调用 时t.Errorf(),它会在副本上注册错误,所以测试框架不会看到这个Errorf()调用。


“最终”解决方案很简单:使用类型转换,但不转换*t,而是转换t本身(它是一个指针)。当然*t不能转换为myT,只能转换为*myT。并且这种类型需要用括号括起来(以避免歧义):


func TestSomething(t *testing.T) {

    my := (*myT)(t)

    my.assert(0)

}

现在我们很高兴,一切都按预期进行。


注意:myT.assert()如果不想调用多个方法,也可以在一行中调用myT:


func TestSomething(t *testing.T) {

    (*myT)(t).assert(0)

}


查看完整回答
反对 回复 2022-01-04
?
蛊毒传说

TA贡献1895条经验 获得超3个赞

您可以使用嵌入来添加所有者方法:


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)

}


查看完整回答
反对 回复 2022-01-04
  • 2 回答
  • 0 关注
  • 195 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信