Golang实现基础功能与单元测试的最佳实践
Golang实现基础功能与单元测试的最佳实践 我希望开发各种基础且实用的Go函数,以便日后在Go程序中复用。以下是一些例子:
- 检查磁盘上是否存在特定文件
- 检查磁盘上是否存在特定目录
- 在指定位置创建文件
- 在指定位置创建目录
- 读取数组并打印所有值及其索引
- 搜索数组中是否存在特定值
- 检查主机是否具有互联网连接
- 检查是否能从URL获取HTTP 200状态码
- 从URL下载文件
- 解压文件
- 等等,等等……
所有这些函数都应该是跨平台的(Windows、Linux、Mac),并且都应该有单元测试。我对单元测试经验不足,因此不确定如何通过模拟文件系统来测试诸如“文件是否存在”或“下载文件”这类功能。如果您能提供类似的示例(例如您的库)或任何相关的技巧/建议——特别是关于测试方面的——我将不胜感激。
我还希望使用日志库,以便区分 info、error 和 debug 级别的日志。您推荐使用哪个库来实现这个功能呢?
提前感谢
更多关于Golang实现基础功能与单元测试的最佳实践的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于Golang实现基础功能与单元测试的最佳实践的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
以下是一些基础功能的Go实现示例及其单元测试,使用标准库和stretchr/testify进行测试,并推荐使用zap作为日志库。
1. 文件系统操作
// fileutil/fileutil.go
package fileutil
import (
"os"
"path/filepath"
)
// FileExists 检查文件是否存在
func FileExists(path string) bool {
_, err := os.Stat(path)
return !os.IsNotExist(err)
}
// DirExists 检查目录是否存在
func DirExists(path string) bool {
info, err := os.Stat(path)
if os.IsNotExist(err) {
return false
}
return info.IsDir()
}
// CreateFile 创建文件
func CreateFile(path string) error {
dir := filepath.Dir(path)
if err := os.MkdirAll(dir, 0755); err != nil {
return err
}
file, err := os.Create(path)
if err != nil {
return err
}
return file.Close()
}
// CreateDir 创建目录
func CreateDir(path string) error {
return os.MkdirAll(path, 0755)
}
2. 数组操作
// sliceutil/sliceutil.go
package sliceutil
import "fmt"
// PrintWithIndex 打印数组元素和索引
func PrintWithIndex(arr []interface{}) {
for i, v := range arr {
fmt.Printf("Index: %d, Value: %v\n", i, v)
}
}
// Contains 检查数组是否包含特定值
func Contains(arr []interface{}, target interface{}) bool {
for _, v := range arr {
if v == target {
return true
}
}
return false
}
3. 网络操作
// netutil/netutil.go
package netutil
import (
"io"
"net/http"
"os"
"time"
)
// HasInternetConnection 检查网络连接
func HasInternetConnection() bool {
client := http.Client{Timeout: 5 * time.Second}
_, err := client.Get("https://www.google.com")
return err == nil
}
// IsURLReachable 检查URL是否可达
func IsURLReachable(url string) bool {
client := http.Client{Timeout: 10 * time.Second}
resp, err := client.Get(url)
if err != nil {
return false
}
defer resp.Body.Close()
return resp.StatusCode == http.StatusOK
}
// DownloadFile 下载文件
func DownloadFile(url, filepath string) error {
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
out, err := os.Create(filepath)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, resp.Body)
return err
}
4. 单元测试示例
// fileutil/fileutil_test.go
package fileutil
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestFileExists(t *testing.T) {
// 创建临时文件
tmpfile, err := os.CreateTemp("", "testfile")
require.NoError(t, err)
defer os.Remove(tmpfile.Name())
// 测试文件存在
assert.True(t, FileExists(tmpfile.Name()))
// 测试文件不存在
assert.False(t, FileExists("/nonexistent/path/file.txt"))
}
func TestDirExists(t *testing.T) {
// 创建临时目录
tmpdir, err := os.MkdirTemp("", "testdir")
require.NoError(t, err)
defer os.RemoveAll(tmpdir)
// 测试目录存在
assert.True(t, DirExists(tmpdir))
// 测试目录不存在
assert.False(t, DirExists("/nonexistent/path"))
// 测试路径是文件而不是目录
tmpfile, err := os.CreateTemp("", "testfile")
require.NoError(t, err)
defer os.Remove(tmpfile.Name())
assert.False(t, DirExists(tmpfile.Name()))
}
func TestCreateFile(t *testing.T) {
tmpdir, err := os.MkdirTemp("", "testcreate")
require.NoError(t, err)
defer os.RemoveAll(tmpdir)
filepath := filepath.Join(tmpdir, "subdir", "test.txt")
// 测试创建文件
err = CreateFile(filepath)
assert.NoError(t, err)
assert.True(t, FileExists(filepath))
}
// netutil/netutil_test.go
package netutil
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
func TestIsURLReachable(t *testing.T) {
// 创建测试服务器
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}))
defer server.Close()
// 测试可达URL
assert.True(t, IsURLReachable(server.URL))
// 测试不可达URL
assert.False(t, IsURLReachable("http://localhost:9999/nonexistent"))
}
func TestDownloadFile(t *testing.T) {
// 创建测试服务器
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("test content"))
}))
defer server.Close()
// 创建临时文件路径
tmpfile, err := os.CreateTemp("", "downloadtest")
require.NoError(t, err)
tmpfile.Close()
defer os.Remove(tmpfile.Name())
// 测试下载
err = DownloadFile(server.URL, tmpfile.Name())
assert.NoError(t, err)
// 验证文件内容
content, err := os.ReadFile(tmpfile.Name())
assert.NoError(t, err)
assert.Equal(t, "test content", string(content))
}
5. 日志配置
// logger/logger.go
package logger
import (
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
var Log *zap.Logger
func InitLogger(debug bool) error {
var config zap.Config
if debug {
config = zap.NewDevelopmentConfig()
config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
} else {
config = zap.NewProductionConfig()
}
logger, err := config.Build()
if err != nil {
return err
}
Log = logger
return nil
}
// 使用示例
func ExampleUsage() {
// 初始化
if err := InitLogger(true); err != nil {
panic(err)
}
defer Log.Sync()
// 记录日志
Log.Info("程序启动")
Log.Debug("调试信息", zap.String("key", "value"))
Log.Error("错误发生", zap.Error(errors.New("test error")))
}
6. go.mod 依赖
module myutils
go 1.21
require (
go.uber.org/zap v1.26.0
github.com/stretchr/testify v1.8.4
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.uber.org/multierr v1.10.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
测试说明:
- 使用
testify/assert进行断言 - 文件测试使用临时目录避免污染系统
- 网络测试使用
httptest模拟服务器 - 通过接口抽象使代码可测试
- 使用
t.Cleanup()或defer进行资源清理
日志库推荐使用Uber的zap,性能高且功能完整。对于测试,stretchr/testify提供了丰富的断言和mock功能。

