Golang校验表格测试仅在有效结构体上失败
Golang校验表格测试仅在有效结构体上失败 // 这是在验证测试中
type Report struct {
SysrptID json.Number `json:"SysrptID" validate:"required"`
Name string `json:"Name" validate:"required"`
Description string `json:"Description"`
FileName string `json:"FileName"`
RptType string `json:"RptType" validate:"oneof=AIS MDR CTE MCM GEN RAL DOC"`
Category []string
}
// 这是我的验证代码:
import (
"fmt"
"github.com/go-playground/validator"
"regexp"
)
// ValidationError 包装了验证器的 FieldError,这样我们就不会将其暴露给外部代码
type ValidationError struct {
validator.FieldError
}
func (v ValidationError) Error() string {
return fmt.Sprintf(
"Key: '%s' Error: Field validation for '%s' failed on the '%s' tag",
v.Namespace(),
v.Field(),
v.Tag(),
)
}
// ValidationErrors 是 ValidationError 的集合
type ValidationErrors []ValidationError
// Errors 将切片转换为字符串切片
func (v ValidationErrors) Errors() []string {
errs := []string{}
for _, err := range v {
errs = append(errs, err.Error())
}
return errs
}
// Validation 包含
type Validation struct {
validate *validator.Validate
}
// NewValidation 创建一个新的 Validation 类型
func NewValidation() *Validation {
validate := validator.New()
//validate.RegisterValidation("sku", validateSKU)
return &Validation{validate}
}
// Validate 验证项目
// 有关更多详细信息,返回的错误可以转换为 validator.ValidationErrors 集合
//
// if ve, ok := err.(validator.ValidationErrors); ok {
// fmt.Println(ve.Namespace())
// fmt.Println(ve.Field())
// fmt.Println(ve.StructNamespace())
// fmt.Println(ve.StructField())
// fmt.Println(ve.Tag())
// fmt.Println(ve.ActualTag())
// fmt.Println(ve.Kind())
// fmt.Println(ve.Type())
// fmt.Println(ve.Value())
// fmt.Println(ve.Param())
// fmt.Println()
// }
func (v *Validation) Validate(i interface{}) ValidationErrors {
errs := v.validate.Struct(i).(validator.ValidationErrors)
// 我认为问题出在这里 :frowning:
if len(errs) == 0 {
return nil
}
var returnErrs []ValidationError
for _, err := range errs {
// 将 FieldError 转换为我们定义的 ValidationError 并追加到切片中
ve := ValidationError{err.(validator.FieldError)}
returnErrs = append(returnErrs, ve)
}
return returnErrs
}
// validateSKU 未使用,仅作为示例
func validateSKU(fl validator.FieldLevel) bool {
// SKU 必须为 abc-abc-abc 格式
re := regexp.MustCompile(`[a-z]+-[a-z]+-[a-z]+`)
sku := re.FindAllString(fl.Field().String(), -1)
if len(sku) == 1 {
return true
}
return false
}
// 验证器结束
// 当我运行这个测试时,对于一个[我认为]应该是有效的报告,程序发生了恐慌 // 它从未进入 if 语句,不确定我做错了什么 // 那些验证失败的结构体工作得很好。 // 恐慌信息是: // 2021/02/17 08:13:36 panic occurred: interface conversion: error is // nil, not validator.ValidationErrors
func TestReportsValidator(t *testing.T) {
tests := map[string]struct {
input Report
want int
}{
//"just id": {input: Report{SysrptID: "1"}, want: 2},
//"just name": {input: Report{Name: "test report"}, want: 2},
//"none": {input: Report{}, want: 3},
"valid": {input: Report{SysrptID: "1", Name: "test", RptType: "RAL"}, want: 0},
//"trailing sep": {input: Report{}, want: 1},
}
for name, tc := range tests {
fmt.Println(name, tc.input, tc.want)
t.Run(name, func(t *testing.T) {
v := NewValidation()
defer func() {
if err := recover(); err != nil {
log.Println("panic occurred:", err)
}
}()
fe := v.Validate(tc.input)
if fe != nil {
assert.Len(t, fe, tc.want)
}
//diff := cmp.Diff(tc.want, got)
//if diff != "" {
// t.Fatalf(diff)
//}
})
}
}
更多关于Golang校验表格测试仅在有效结构体上失败的实战教程也可以访问 https://www.itying.com/category-94-b0.html
请将你的代码用三个反引号包裹起来,就像这样:
code here
Go 语言中的逗号 ok 模式派上了用场,这意味着如果没有验证问题,我可以返回 nil。某个 YouTube 代码中存在一个严重的错误。通过一个测试修复了它。这个问题发生在我服务中添加一个本应通过验证的项目时。太酷了。
func (v *Validation) Validate(i interface{}) ValidationErrors {
var returnErrs []ValidationError
if errs, ok := v.validate.Struct(i).(validator.ValidationErrors); ok {
if errs != nil {
for _, err := range errs {
if fe, ok := err.(validator.FieldError); ok {
ve := ValidationError{fe}
returnErrs = append(returnErrs, ve)
}
}
}
}
return returnErrs
}
问题出现在 Validate 方法中的类型断言。当验证通过时,v.validate.Struct(i) 返回 nil,但代码试图将其断言为 validator.ValidationErrors,这会导致 panic。
以下是修复后的 Validate 方法:
func (v *Validation) Validate(i interface{}) ValidationErrors {
err := v.validate.Struct(i)
if err == nil {
return nil
}
// 只有当 err 不是 nil 时才进行类型断言
errs, ok := err.(validator.ValidationErrors)
if !ok {
// 处理非验证错误的情况
return ValidationErrors{
ValidationError{fieldError: err},
}
}
var returnErrs []ValidationError
for _, err := range errs {
ve := ValidationError{err}
returnErrs = append(returnErrs, ve)
}
return returnErrs
}
还需要更新 ValidationError 结构体以处理非 FieldError 的情况:
type ValidationError struct {
fieldError error
}
func (v ValidationError) Error() string {
if fe, ok := v.fieldError.(validator.FieldError); ok {
return fmt.Sprintf(
"Key: '%s' Error: Field validation for '%s' failed on the '%s' tag",
fe.Namespace(),
fe.Field(),
fe.Tag(),
)
}
return v.fieldError.Error()
}
这样修改后,当验证通过时不会发生 panic,测试用例也能正确处理有效结构体。

