英文:
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
}{
&Params{
Field1: "invalid_0" // <--- making sure that this invalid field is caught
Field2: "valid"
Field3: "valid"
...
Field10: "valid"
},
&Params{
Field1: "invalid_1" // <--- another invalid case
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)
}
}
}
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 = "invalid_0"
})
The CreateParamsWith
might look like this:
func CreateParamsWith(modifyParams func(*Params)) (*Params) {
params := &Params{
Field1: "valid",
Field2: "valid",
Field3: "valid",
Field4: "valid",
Field5: "valid",
}
modifyParams(params)
return params
}
Full working code here: https://play.golang.org/p/U0xhtIbQfy
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论