Go Pact消费者测试中UUID类型字段返回字节数组问题求解
问题根因
Pact Go的dsl.Match方法通过反射解析结构体字段的底层类型生成匹配规则,github.com/google/uuid.UUID的底层类型是[16]byte数组,所以默认生成的规则会把ID字段匹配为字节数组,和实际JSON序列化后的UUID字符串格式不匹配,就会出现mock返回字节数组的问题。
方案1:显式覆盖UUID字段的匹配规则(最推荐,无侵入业务代码)
不需要修改业务定义的结构体,仅调整测试代码即可。如果结构体字段较多,可以先通过dsl.Match生成默认的匹配规则,再单独覆盖UUID字段的规则为字符串格式+UUID正则匹配:
// 先生成默认的结构体匹配规则 bodyMatcher := dsl.Match(&Foo{}).(dsl.MapMatcher) // 单独覆盖ID字段,指定为UUID格式的字符串匹配 bodyMatcher["id"] = dsl.Regex( "3fa85f64-5717-4562-b3fc-2c963f66afa6", "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", ) pact. AddInteraction(). Given("A result exists"). UponReceiving("A request to get all results"). WithRequest(dsl.Request{ Method: "get", Path: dsl.String("/v1"), }). WillRespondWith(dsl.Response{ Status: 200, Headers: dsl.MapMatcher{"Content-Type": dsl.String("application/json")}, Body: bodyMatcher, })
方案2:自定义UUID别名类型(适合项目中大量使用UUID字段的场景)
如果项目内很多结构体都用到了uuid.UUID类型,可以定义一个自定义别名类型,实现Pact的匹配接口和原有的JSON序列化接口,后续所有用到UUID的地方替换为自定义类型即可,不用再单独调整每个测试的匹配规则:
import ( "github.com/google/uuid" "github.com/pact-foundation/pact-go/dsl" ) // 自定义UUID类型,完全兼容google/uuid的所有能力 type UUID uuid.UUID // 实现Pact匹配器接口,指定该类型匹配UUID格式字符串 func (u UUID) Match() dsl.Matcher { return dsl.Regex( uuid.UUID(u).String(), "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", ) } // 保持原有JSON序列化能力 func (u UUID) MarshalJSON() ([]byte, error) { return uuid.UUID(u).MarshalJSON() } func (u *UUID) UnmarshalJSON(data []byte) error { return (*uuid.UUID)(u).UnmarshalJSON(data) } // 业务结构体替换为自定义UUID类型 type Foo struct { ID UUID `json:"id"` Name string `json:"name"` Description string `json:"description"` }
修改后原有的测试代码不需要调整,直接调用dsl.Match(&Foo{})就会生成正确的字符串格式匹配规则。
方案3:字段类型改为string(不推荐)
也就是你想到的方案,将ID字段定义为string类型,业务代码中手动做string到uuid.UUID的转换。该方案不需要适配Pact,但会增加业务层的类型转换逻辑和异常处理成本,仅在前两种方案无法落地时考虑。
内容的提问来源于stack exchange,提问作者beerye
相关产品推荐
相关产品推荐

