• 不会写单元测试的程序员不是一个合格的滴滴司机


    go内置了一套单元测试机制: 利用 go test测试命令和一套按照约定发方式编写的测试函数。

    在包目录内,所有以_test.go为后缀名编写的go文件不会参与go build的编译过程.

    本文所有的代码均放置了带缓冲区的异步写日志库

    go test 一共三种测试函数:

    • 标准测试函数, 函数以Test为前缀,用于测试逻辑行为正确性, go test 会报告测试结果 PASS、FAIL
    • 基准测试函数是以Benchmark为前缀的函数,用于衡量函数性能, 拿到平均执行时间
    • 样例函数, 提供一个编译器保证正确性的示例文档

    标准测试函数

    • 导入testing包
    • 以Test开头,除Test开头的自定义函数需要首字母大写
    • 函数参数t *testing.T用于报告测试失败和附加的日志信息
    func TestWriteLog(t *testing.T) {
    
    	l := logrus.New()
    	l.SetFormatter(&logrus.TextFormatter{
    		DisableTimestamp: true,
    	})
    	l.SetOutput(io.Discard) // Send all logs to nowhere by default
    	bh := &BufferedWriterHook{Writer: os.Stdout}
    	defer bh.Stop()
    
    	err := bh.Fire(&logrus.Entry{Logger: l, Level: logrus.InfoLevel, Message: "test" + time.Now().Format(time.RFC3339)})
    	if err != nil {
    		t.Error(t.Name() + " FAIL")
    	}
    }
    

    基准测试函数

    • 以Benchmark开头
    • b.N表示迭代次数,不固定,确保至少执行1s
    func BenchmarkFire(b *testing.B) {
    	l := logrus.New()
    	l.SetFormatter(&logrus.TextFormatter{
    		DisableTimestamp: true,
    	})
    
    	logf, err := os.OpenFile("./log.txt", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0600)
    	if err != nil {
    		panic(err)
    	}
    	defer logf.Close()
    
    	bh := &BufferedWriterHook{Writer: logf}
    	defer bh.Stop()
    
    	b.ResetTimer() // 重置计时器,忽略前面的准备时间
    	for n := 0; n < b.N; n++ {
    		err := bh.Fire(&logrus.Entry{Logger: l, Level: logrus.InfoLevel, Message: "test" + time.Now().Format(time.RFC3339)})
    		if err != nil {
    			b.Error(b.Name() + " FAIL")
    		}
    	}
    }
    

    go test -bench=. 执行基准测试

    以上如果有单元测试,也会执行,若要忽略单元测试,请执行go test -bench=. -count 5 -run=^#

    //对https://github.com/zwbdzb/logrus-bufferedWriter-hook执行基准测试
    BenchmarkFire-8           940003              1130 ns/op
    BenchmarkFire1-8           53912             19678 ns/op
    

    前者是循环次数,后者是每次循环的平均耗时。

    结果显示 带异步缓冲区的logrus写磁盘能力,是logrus默认同步写磁盘能力的10+倍。

    样例函数

    • 以Example开头
    • 需要在代码内体现预期输出,下方output注释部分。
      go test -run=ExampleHook_default
    func ExampleHook_default() {
    	l := logrus.New()
    	l.SetLevel(logrus.InfoLevel)
    	l.SetFormatter(&logrus.TextFormatter{
    		DisableTimestamp: true,
    	})
    	l.SetOutput(io.Discard) // Send all logs to nowhere by default
    
    	ws := &BufferedWriterHook{Writer: os.Stdout}
    	defer ws.Stop()
    	l.AddHook(ws)
    
    	l.Info("test2")
    	l.Warn("test3")
    	l.Error("test4")
    
    	// Output:
    	// level=info msg=test2
    	// level=warning msg=test3
    	// level=error msg=test4
    }
    

    本文快速记录了golang单元测试、基准测试、样例测试的写法,耗时3h, 有用指数4颗星。

    btw 本文测试源码位于https://github.com/zwbdzb/logrus-bufferedWriter-hook, 这是一个带异步缓冲区的logrus日志Hook,能有效解决logrus默认不支持异步日志带来的写性能问题,欢迎试用,期待你的star。

    下面是相比同步写日志的基准测试结果:大致是原同步写日志的 10s+倍性能。

    -8表示8个CPU线程执行;64819表示总共执行了64819次;19755ns/op,表示每次执行耗时19755纳秒;496/op表示每次执行分配了496字节内存;15 allocs/op表示每次执行分配了15次对象。

  • 相关阅读:
    PIL库的crop函数(图片裁剪操作)
    基于双碳背景和趋势讲述AcrelEMS企业微电网能效管理系统-Susie 周
    企业架构LNMP学习笔记13
    2021年认证杯SPSSPRO杯数学建模C题(第一阶段)破局共享汽车求解全过程文档及程序
    Java继承
    集美大学 - 2840 - 实验10和11 - 编程题
    多张图解,一扫你对多线程问题本质的所有误区
    设计模式——原型模式05
    RocketMQ 关于 No route info of this topic 问题
    [项目构建] 二次封装统一Axios配置 JSTS两个版本实现取消重复请求,超时重发
  • 原文地址:https://www.cnblogs.com/JulianHuang/p/17523100.html