如何在Go中定义一个与给定字符串变量等效的validator.FieldLevel?

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

How to define a validator.Fieldlevel equivalent of a given string variable in Go?

问题

我正在使用Go的validator包验证我的配置文件。

我从配置文件中读取一个字段(createTime),将其作为string类型,并希望确保它是一个有效的时间duration

type Config struct{
    ...
    CreateTime   string `yaml:"createTime" validate:"duration,required"`
    ...
}

因此,我编写了一个自定义验证函数如下:

import (
    "time"
    "github.com/go-playground/validator/v10"
)

// isValidDuration是一个自定义验证函数,它将检查给定的字符串是否是一个有效的时间持续时间
func isValidDuration(fl validator.FieldLevel) bool {
    if _, err := time.ParseDuration(fl.Field().String()); err != nil {
        return false
    }
    return true
}

我将其用于验证如下:

func (configObject *Config) Validate() error {

    // 验证配置
    validate := validator.New()
    if err := validate.RegisterValidation("duration", isValidDuration); err != nil {
        return err
    }
    return validate.Struct(configObject)
}

自定义验证器正常工作,我想为isValidDuration函数编写一个单元测试。以下是IDE生成的单元测试样板代码:

import (
    "testing"
    "github.com/go-playground/validator/v10"
)

func Test_isValidDuration(t *testing.T) {
    type args struct {
        fl validator.FieldLevel
    }
    var tests = []struct {
        name string
        args args
        want bool
    }{
        // TODO: 添加测试用例。
        {name: "positive", args: ???????, want: true},
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            if got := isValidDuration(tt.args.fl); got != tt.want {
                t.Errorf("isValidDuration() = %v, want %v", got, tt.want)
            }
        })
    }
}

我是Go的新手,不确定如何在上述测试用例的args字段中传递参数。如何创建一个包含一个validator.FieldLevel字段的结构体?

理想情况下,我想传递类似于"10m"的内容作为args,并且由于它是一个有效的时间持续时间,我期望isValidDuration的输出为true,因为"10m"是一个有效的持续时间。我尝试了这个:{name: "positive", args: struct{ fl validator.FieldLevel }{fl: "10m"}, want: true},但是得到了这个错误:'"10m"'(类型为string)无法表示为类型validator.FieldLevel

如何创建一个值等于"10m"validator.FieldLevel变量?有人可以帮帮我吗?

英文:

I'm validating my config file using Go's validator package

One of the fields(createTime) from the config file I'm reading as a string, and want to make sure that it is a valid time duration:

type Config struct{
    ...
    CreateTime   string `yaml:"createTime" validate:"duration,required"`
    ...
}

So, I have written a custom validation function as follows:

import (
    "time"
    "github.com/go-playground/validator/v10"
)

// isValidDuration is a custom validation function, and it will check if the given string is a valid time duration
func isValidDuration(fl validator.FieldLevel) bool {
	if _, err := time.ParseDuration(fl.Field().String()); err != nil {
		return false
	}
	return true
}

Which I'm using for validation as follows:

func (configObject *Config) Validate() error {

	// Validate configurations
	validate := validator.New()
	if err := validate.RegisterValidation("duration", isValidDuration); err != nil {
		return err
	}
	return validate.Struct(configObject)
}

The custom validator is working fine and I want to write a unit test for isValidDuration function. Following is the unit test boilerplate generated by IDE:

import (
	"testing"
	"github.com/go-playground/validator/v10"
)

func Test_isValidDuration(t *testing.T) {
	type args struct {
		fl validator.FieldLevel
	}
	var tests = []struct {
		name string
		args args
		want bool
	}{
		// TODO: Add test cases.
		{name: "positive", args: ???????, want: true},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := isValidDuration(tt.args.fl); got != tt.want {
				t.Errorf("isValidDuration() = %v, want %v", got, tt.want)
			}
		})
	}
}

I'm new to Go and not sure what to pass in the args field of the testcase above. How do I create a struct containing one validator.FieldLevel field?

Ideally, I would like to pass something like "10m" as args and since it is a valid time duration, would expect the output of isValidDuration as true since "10m" is a valid duration.
I'm trying this: {name: "positive", args: struct{ fl validator.FieldLevel }{fl: "10m"}, want: true} but getting this ereor: '"10m"' (type string) cannot be represented by the type validator.FieldLevel

How do I create a validator.FieldLevel variable with value equivalent to "10m"? Could someone please help me out?

答案1

得分: 1

问题1

一个语义问题,fl不是String类型。

{
  name: "positive",
  args: args{
    fl: validator.FieldLevel{
       // ....
    },
  },
  want: true,
},

问题2

如何使用validator.FieldLevel

在代码库中,我们可以看到FieldLevel是一个接口,你需要创建一个未导出的、不应该被用户使用的结构体validate

type FieldLevel interface

// ...

var _ FieldLevel = new(validate)

回答

所以,最好像validator包的UT一样编写你的UT。不要使用IDE中的代码!

// 看一下这个UT
// github.com/go-playground/validator/v10@v10.10.0/validator_test.go
func TestKeysCustomValidation(t *testing.T) {
英文:

problem1

A language semantic problem, fl is not the type String.

{
  name: "positive", 
  args: args{
    fl: validator.FieldLevel{
       // ....
    },
  }, 
  want: true,
},

problem2

How to use validator.FieldLevel.

In code base, we can see FieldLevel is a interface, and you need create struct validate, which is not exported and not supposed to be used by user.

type FieldLevel interface

// ...

var _ FieldLevel = new(validate)

answer

So, you'd best to write your UT like UT of validator package. Don't use the code from your IDE!

// have a look at this UT
// github.com/go-playground/validator/v10@v10.10.0/validator_test.go
func TestKeysCustomValidation(t *testing.T) {

huangapple
  • 本文由 发表于 2022年2月6日 22:50:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/71008310.html
匿名

发表评论

匿名网友

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

确定