在Golang项目里,配置加载通常同时支持从本地配置文件和环境变量读取参数,为了保证配置读取逻辑的正确性,我们需要编写对应的单元测试验证不同读取路径的返回结果是否符合预期,避免出现配置读取错误导致的线上故障。

配置加载基础结构搭建
首先我们需要定义一个配置结构体,以及对应的加载逻辑,支持从YAML配置文件和环境变量读取配置,环境变量优先级高于配置文件。
package config
import (
"os"
"gopkg.in/yaml.v3"
)
// AppConfig 应用配置结构体
type AppConfig struct {
ServerPort string `yaml:"server_port" env:"SERVER_PORT"`
DBHost string `yaml:"db_host" env:"DB_HOST"`
DBPort string `yaml:"db_port" env:"DB_PORT"`
}
// LoadConfig 加载配置,先读配置文件,再用环境变量覆盖
func LoadConfig(configPath string) (*AppConfig, error) {
cfg := &AppConfig{}
// 读取配置文件
data, err := os.ReadFile(configPath)
if err != nil {
return nil, err
}
err = yaml.Unmarshal(data, cfg)
if err != nil {
return nil, err
}
// 读取环境变量覆盖配置
if port := os.Getenv("SERVER_PORT"); port != "" {
cfg.ServerPort = port
}
if host := os.Getenv("DB_HOST"); host != "" {
cfg.DBHost = host
}
if port := os.Getenv("DB_PORT"); port != "" {
cfg.DBPort = port
}
return cfg, nil
}
测试环境准备
测试配置加载逻辑需要准备临时配置文件和临时环境变量,测试完成后需要清理这些临时资源,避免影响其他测试用例。
临时配置文件创建
我们可以在测试用例执行前创建临时的YAML配置文件,测试结束后删除该文件。
环境变量管理
测试前设置需要的环境变量,测试结束后恢复原来的环境变量值,避免污染全局环境。
编写测试用例
我们使用Golang内置的testing包编写测试用例,覆盖配置文件读取、环境变量读取、优先级校验三个核心场景。
package config
import (
"os"
"path/filepath"
"testing"
)
// TestLoadConfigFromFile 测试从配置文件读取配置
func TestLoadConfigFromFile(t *testing.T) {
// 创建临时配置文件
tmpDir := t.TempDir()
configPath := filepath.Join(tmpDir, "config.yaml")
configContent := `
server_port: "8080"
db_host: "127.0.0.1"
db_port: "3306"
`
err := os.WriteFile(configPath, []byte(configContent), 0644)
if err != nil {
t.Fatalf("创建临时配置文件失败: %v", err)
}
// 清除可能影响测试的环境变量
os.Unsetenv("SERVER_PORT")
os.Unsetenv("DB_HOST")
os.Unsetenv("DB_PORT")
cfg, err := LoadConfig(configPath)
if err != nil {
t.Fatalf("加载配置失败: %v", err)
}
// 验证配置值
if cfg.ServerPort != "8080" {
t.Errorf("期望server_port为8080,实际为%s", cfg.ServerPort)
}
if cfg.DBHost != "127.0.0.1" {
t.Errorf("期望db_host为127.0.0.1,实际为%s", cfg.DBHost)
}
if cfg.DBPort != "3306" {
t.Errorf("期望db_port为3306,实际为%s", cfg.DBPort)
}
}
// TestLoadConfigFromEnv 测试从环境变量读取配置
func TestLoadConfigFromEnv(t *testing.T) {
// 创建临时配置文件,配置值和环境变量不同
tmpDir := t.TempDir()
configPath := filepath.Join(tmpDir, "config.yaml")
configContent := `
server_port: "8080"
db_host: "127.0.0.1"
db_port: "3306"
`
err := os.WriteFile(configPath, []byte(configContent), 0644)
if err != nil {
t.Fatalf("创建临时配置文件失败: %v", err)
}
// 设置环境变量
os.Setenv("SERVER_PORT", "9090")
os.Setenv("DB_HOST", "192.168.0.1")
os.Setenv("DB_PORT", "5432")
// 测试结束后恢复环境变量
defer func() {
os.Unsetenv("SERVER_PORT")
os.Unsetenv("DB_HOST")
os.Unsetenv("DB_PORT")
}()
cfg, err := LoadConfig(configPath)
if err != nil {
t.Fatalf("加载配置失败: %v", err)
}
// 验证环境变量的值覆盖了配置文件的值
if cfg.ServerPort != "9090" {
t.Errorf("期望server_port为9090,实际为%s", cfg.ServerPort)
}
if cfg.DBHost != "192.168.0.1" {
t.Errorf("期望db_host为192.168.0.1,实际为%s", cfg.DBHost)
}
if cfg.DBPort != "5432" {
t.Errorf("期望db_port为5432,实际为%s", cfg.DBPort)
}
}
// TestLoadConfigFileNotExist 测试配置文件不存在的场景
func TestLoadConfigFileNotExist(t *testing.T) {
_, err := LoadConfig("not_exist_config.yaml")
if err == nil {
t.Error("期望配置文件不存在时返回错误,实际未返回错误")
}
}
测试执行与结果校验
在项目根目录执行go test -v ./config命令即可运行上述测试用例,查看测试结果是否符合预期。如果所有测试用例都通过,说明配置加载的文件读取和环境变量读取逻辑都是正确的,优先级处理也符合预期。
实际开发中还可以根据需求扩展更多测试场景,比如配置文件格式错误、环境变量值为空等边界场景,进一步提升配置加载逻辑的可靠性。