You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言结构体单元测试:完善VSCode生成的YAML解析测试用例

完善Go YAML解析与属性校验测试的方案

你已经搭好了基础的测试架子,但要全面覆盖YAML解析和属性校验的所有场景,还得从测试用例维度、错误验证逻辑、代码拆分这几个方面入手。下面是具体的完善步骤:

1. 补充覆盖全场景的测试用例

当前的测试只覆盖了“合法YAML解析成功”这一种情况,要覆盖所有逻辑,得补充以下几类用例:

  • 正常合法场景(不同结构的有效YAML)
  • YAML格式错误场景(语法、缩进问题)
  • 属性校验失败场景(必填字段缺失、类型不匹配、枚举值非法等)
  • 边界场景(空文件、超大字段、特殊字符输入)

修改后的测试用例结构体可以这样写:

type args struct {
	ztrFile string
}

// 扩展测试用例,覆盖全场景
tests := []struct {
	name        string
	args        args
	wantOut     ZTR
	wantErr     bool          // 标记是否预期执行报错
	errContains string        // 预期错误信息中必须包含的关键词
}{
	// 正常场景:完整合法的YAML配置
	{
		name:    "valid_full_config",
		args:    args{ztrFile: "./testdata/valid_full.yaml"},
		wantOut: expectedFullZTR, // 提前构造好预期的ZTR实例
		wantErr: false,
	},
	// YAML格式错误:冒号后未加空格,触发语法解析失败
	{
		name:        "invalid_yaml_syntax",
		args:        args{ztrFile: "./testdata/invalid_syntax.yaml"},
		wantErr:     true,
		errContains: "yaml: syntax error",
	},
	// 属性校验失败:必填字段modules缺失
	{
		name:        "missing_required_modules",
		args:        args{ztrFile: "./testdata/missing_modules.yaml"},
		wantErr:     true,
		errContains: "required field 'modules' is missing",
	},
	// 属性校验失败:字段类型不匹配(比如把数字类型的端口写成字符串)
	{
		name:        "wrong_field_type",
		args:        args{ztrFile: "./testdata/wrong_type.yaml"},
		wantErr:     true,
		errContains: "cannot unmarshal string into Go struct field",
	},
	// 边界场景:空文件
	{
		name:        "empty_yaml_file",
		args:        args{ztrFile: "./testdata/empty.yaml"},
		wantErr:     true,
		errContains: "yaml: unmarshal errors",
	},
}

2. 完善测试逻辑,增加错误验证

原来的测试只处理了成功场景,现在要适配错误场景的验证。首先要确保你的parseFile函数能返回错误(如果原来没返回,得先修改它,让解析或校验失败时返回对应的error),然后修改测试循环:

import (
	"reflect"
	"strings"
	"testing"
)

for _, tt := range tests {
	t.Run(tt.name, func(t *testing.T) {
		// 假设parseFile现在返回(out ZTR, err error)
		gotOut, err := parseFile(tt.args.ztrFile)

		// 先验证错误是否符合预期
		if (err != nil) != tt.wantErr {
			t.Errorf("parseFile() error = %v, wantErr %v", err, tt.wantErr)
			return
		}

		// 如果预期有错误,验证错误信息是否包含指定关键词
		if tt.wantErr {
			if !strings.Contains(err.Error(), tt.errContains) {
				t.Errorf("parseFile() error message = %q, should contain %q", err.Error(), tt.errContains)
			}
			return // 错误场景无需验证返回值
		}

		// 成功场景验证返回值是否与预期一致
		if !reflect.DeepEqual(gotOut, tt.wantOut) {
			t.Errorf("parseFile() = %+v, want %+v", gotOut, tt.wantOut)
		}
	})
}

3. 额外优化建议

  • 提前构造预期结构体:对于合法场景的wantOut,可以在测试文件顶部提前构造好预期的ZTR实例,比如:
    var expectedFullZTR = ZTR{
        Modules: []Module{
            {Name: "auth-service", Version: "v2.1.0"},
            {Name: "payment-service", Version: "v1.5.3"},
        },
        // 填充其他顶层字段
    }
    
  • 拆分校验逻辑单独测试:如果属性校验逻辑复杂,建议把它从parseFile中抽成独立函数(比如validateZTR(z ZTR) error),然后针对这个函数写专门的单元测试——直接构造各种合法/非法的ZTR结构体传入,不需要依赖YAML文件,测试效率更高:
    func TestValidateZTR(t *testing.T) {
        tests := []struct {
            name        string
            inputZTR    ZTR
            wantErr     bool
            errContains string
        }{
            {
                name: "valid_ztr_with_correct_versions",
                inputZTR: ZTR{
                    Modules: []Module{{Name: "user-service", Version: "v1.0.0"}},
                },
                wantErr: false,
            },
            {
                name: "invalid_version_format",
                inputZTR: ZTR{
                    Modules: []Module{{Name: "order-service", Version: "invalid-version"}},
                },
                wantErr:     true,
                errContains: "invalid version format: must follow semver rules",
            },
        }
    
        for _, tt := range tests {
            t.Run(tt.name, func(t *testing.T) {
                err := validateZTR(tt.inputZTR)
                if (err != nil) != tt.wantErr {
                    t.Errorf("validateZTR() error = %v, wantErr %v", err, tt.wantErr)
                    return
                }
                if tt.wantErr && !strings.Contains(err.Error(), tt.errContains) {
                    t.Errorf("validateZTR() error message = %q, should contain %q", err.Error(), tt.errContains)
                }
            })
        }
    }
    
  • 保持testdata目录整洁:继续把所有测试用的YAML文件放在testdata目录下,避免和业务代码混淆,也方便后续维护。

内容的提问来源于stack exchange,提问作者user9528667

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:59:28