测试时如何避免struct指针值变更影响子测试外部?
解决Go子测试中结构体指针字段修改污染外部值的问题
我明白你遇到的问题了——自动生成的结构体里带指针字段,子测试里修改指针指向的值后,居然影响到了其他子测试,导致断言失败。这是因为Go的结构体值拷贝只会复制指针本身,而不是它指向的内存内容,所以所有子测试里的结构体其实共享同一个Color指针指向的字符串。
下面给你两种可行的解决方案,都不需要修改自动生成的结构体:
1. 手动复制指针字段(简单场景适用)
在每个子测试里,不要直接赋值原结构体,而是为指针字段创建新的内存空间,拷贝原值后再修改。这样每个子测试的结构体都会拥有独立的指针,修改不会互相影响:
package main import ( "testing" ) func TestTyre(t *testing.T) { type Tyre struct { Color *string } type Vehicle struct { Tyre Tyre } color := "black" tyreForTest := Tyre{Color: &color} expectedTyreColor := color t.Run("negativeTest", func(t *testing.T) { // 为Color字段创建新的指针,复制原值 newColor := *tyreForTest.Color tyre := Tyre{Color: &newColor} *tyre.Color = "blue" // 现在修改的是独立的内存空间 vehicle := Vehicle{Tyre: tyre} actualTyreColor := vehicle.Tyre.Color ok := (expectedTyreColor == *actualTyreColor) if ok { t.Error("Color should be blue") } }) t.Run("positiveTest", func(t *testing.T) { // 同样创建独立的指针实例,避免受其他子测试影响 newColor := *tyreForTest.Color tyre := Tyre{Color: &newColor} vehicle := Vehicle{Tyre: tyre} actualTyreColor := vehicle.Tyre.Color ok := (expectedTyreColor == *actualTyreColor) if !ok { t.Error("Color should be black, instead of", *actualTyreColor) } }) }
2. 编写复制辅助函数(复杂结构体适用)
如果结构体的字段很多,手动复制每个指针字段会很繁琐。可以写一个辅助函数来完成深度复制,这样所有子测试都可以复用这个函数:
package main import ( "testing" ) func TestTyre(t *testing.T) { type Tyre struct { Color *string } type Vehicle struct { Tyre Tyre } // 辅助函数:深度复制Tyre结构体 copyTyre := func(src Tyre) Tyre { var dst Tyre if src.Color != nil { // 为Color字段创建新的内存空间 colorVal := *src.Color dst.Color = &colorVal } return dst } color := "black" tyreForTest := Tyre{Color: &color} expectedTyreColor := color t.Run("negativeTest", func(t *testing.T) { tyre := copyTyre(tyreForTest) *tyre.Color = "blue" vehicle := Vehicle{Tyre: tyre} actualTyreColor := vehicle.Tyre.Color ok := (expectedTyreColor == *actualTyreColor) if ok { t.Error("Color should be blue") } }) t.Run("positiveTest", func(t *testing.T) { tyre := copyTyre(tyreForTest) vehicle := Vehicle{Tyre: tyre} actualTyreColor := vehicle.Tyre.Color ok := (expectedTyreColor == *actualTyreColor) if !ok { t.Error("Color should be black, instead of", *actualTyreColor) } }) }
原理说明
Go的结构体值拷贝是浅拷贝:当你执行tyre := tyreForTest时,只会复制Tyre结构体的表层数据,其中的Color指针依然指向原来的字符串内存地址。而我们通过创建新的字符串变量并取地址,相当于给每个子测试的Tyre实例分配了独立的Color内存空间,这样修改就不会扩散到其他子测试了。
内容的提问来源于stack exchange,提问作者subtleseeker
相关产品推荐
相关产品推荐

