为了进行单元测试,可以通过改变结构体字段的值来测试不同的情况。

huangapple go评论139阅读模式
英文:

Varying a struct field for unit testing

问题

我正在尝试对一个具有许多字段的结构体的构造函数进行单元测试。我希望确保构造函数执行所有预期的验证,因此我正在测试单个字段的多个失败场景。

我试图以编程方式实现这一点,所以我正在使用表格测试,但这会导致测试中出现大量的重复和噪音,因为我不得不重复 N 个参数字段,只是为了测试一个字段的错误。

例如:

func NewSomeObject(p *Params) *SomeObject {
  ...
}

type SomeObject struct {
  ..
  Field1 string
  Field2 string
  Field3 string
  ...
  Field10 string
}

func TestNewSomeObject(t *testing.T) {
    tcases := map[string]struct {
        params *Params
        err    error
    }{
        &Params{
          Field1: "invalid_0", // <--- 确保捕获此无效字段
          Field2: "valid",
          Field3: "valid",
          ...
          Field10: "valid",
        },
        &Params{
          Field1: "invalid_1", // <--- 另一个无效情况
          Field2: "valid",
          Field3: "valid",
          ...
          Field10: "valid",
        },
        &Params{
          Field1: "invalid_2",
          Field2: "valid",
          Field3: "valid",
          ...
          Field10: "valid",
        },
        &Params{
          Field1: "invalid_3",
          Field2: "valid",
          Field3: "valid",
          ...
          Field10: "valid",
        },
        ...
        ...
        ...
    }  

    for name, tc := range tcases {
        t.Logf("Running test %s", name)

        s, err := NewSomeObject(tc.params)
        if !reflect.DeepEqual(tc.err, err) {
            t.Fatalf("Got '%v', Expected: '%v'", err, tc.err)
        }
    }
}

有没有更好的方法来改变结构体中的单个字段,而不必重复输入这么多次?

英文:

I'm trying to unit test a constructor for a struct with many fields. I want to make sure that the constructor performs all the expected validations so I am testing single fields for multiple failure scenarios.

I'm trying to do this programatically so I'm using table tests, however this leads to a lot of repetition and noise in the tests as I end up repeating N param fields just to test for the one field error.

For example:

func NewSomeObject(p *Params) *SomeObject {
...
}
type SomeObject struct {
..
Field1 string
Field2 string
Field3 string
...
Field10 string
}
func TestNewSomeObject(t *testing.T) {
tcases := map[string]struct {
params *Params
err    error
}{
&amp;Params{
Field1: &quot;invalid_0&quot; // &lt;--- making sure that this invalid field is caught
Field2: &quot;valid&quot;
Field3: &quot;valid&quot;
...
Field10: &quot;valid&quot;
},
&amp;Params{
Field1: &quot;invalid_1&quot; // &lt;--- another invalid case
Field2: &quot;valid&quot;
Field3: &quot;valid&quot;
...
Field10: &quot;valid&quot;
},
&amp;Params{
Field1: &quot;invalid_2&quot;
Field2: &quot;valid&quot;
Field3: &quot;valid&quot;
...
Field10: &quot;valid&quot;
},
&amp;Params{
Field1: &quot;invalid_3&quot;
Field2: &quot;valid&quot;
Field3: &quot;valid&quot;
...
Field10: &quot;valid&quot;
},
...
...
...
}  
for name, tc := range tcases {
t.Logf(&quot;Running test %s&quot;, name)
s, err := NewSomeObject(tc.params)
if !reflect.DeepEqual(tc.err, err) {
t.Fatalf(&quot;Got &#39;%v&#39;, Expected: &#39;%v&#39;&quot;, err, tc.err)
}
}
}

Is there a better way to vary a single field in the struct without having to repeat the input so many times?

答案1

得分: 2

你可以通过创建一个构造函数来避免重复的代码,该构造函数可以设置所有默认值(有效值)。

构造函数还可以接收一个函数,在返回对象之前对创建的对象进行操作。

这样,你只需要编写逻辑来使特定字段无效,以便进行测试。

要创建一个 Params 对象,你可以这样做:

params1 := CreateParamsWith(func(p *Params) {
p.Field1 = "invalid_0"
})

CreateParamsWith 可能如下所示:

func CreateParamsWith(modifyParams func(*Params)) (*Params) {
params := &Params{	
Field1: "valid",
Field2: "valid",
Field3: "valid",
Field4: "valid",
Field5: "valid",
}
modifyParams(params)
return params
}

完整的可运行代码请参考这里:https://play.golang.org/p/U0xhtIbQfy

英文:

You can avoid repetitive code by creating one constructor that would set up all default values (valid).

The constructor can also receive a function to operate over the created object before returning it.

That way, you only need to code the logic required to invalidate the particular field you'd like to test.

To create a Params object you can just do:

params1 := CreateParamsWith(func(p *Params) {
p.Field1 = &quot;invalid_0&quot;
})

The CreateParamsWith might look like this:

func CreateParamsWith(modifyParams func(*Params)) (*Params) {
params := &amp;Params{	
Field1: &quot;valid&quot;,
Field2: &quot;valid&quot;,
Field3: &quot;valid&quot;,
Field4: &quot;valid&quot;,
Field5: &quot;valid&quot;,
}
modifyParams(params)
return params
}

Full working code here: https://play.golang.org/p/U0xhtIbQfy

huangapple
  • 本文由 发表于 2017年5月23日 01:38:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/44118967.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定