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

68099854ae69e1f8476e279c89bc8a05.gif

go内置了一套单元测试机制:利用go test测试命令和一套按照约定方式编写的测试函数, os:比C#单元/基准测试要方便很多。

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

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

go test 一共三种测试函数:

  • • 标准测试函数, 函数以Test为前缀,用于测试逻辑行为正确性, go test 会报告测试结果 PASS、FAIL

  • • 基准测试函数是以Benchmark为前缀的函数,用于衡量函数性能, 拿到平均执行时间

  • • 示例函数, 提供一个编译器保证正确性的示例文档

1. 标准测试函数
  • • 导入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")
    }
}
2. 基准测试函数
  • • 以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+倍。

3. 示例测试函数
  • • 以Example开头

  • • 示例测试需要体现预期的输出, 下面的绿色注释部分

  • • 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
}

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

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

下面是相比同步写日志的基准测试结果:官方同步写日志的10+倍性能

60eee094b67c7a6c4ebda0cc349ff1d9.png

引用链接

[1] 带缓冲区的异步写日志库: https://github.com/zwbdzb/logrus-bufferedWriter-hook

8cc234e803327d61d5bf6f0b4e5e9789.gif

自古以来,同步/异步都是八股文第一章

自古以来,反射也是兵家必争之地

Go编程快闪之logrus日志库

流量调度、微服务可寻址性和注册中心

摸鱼快报:golang net/http中的雕虫小技

Go语言正/反向代理的姿势

两将军问题和TCP三次握手

点“dc5d2c65e617da448dbef099dcf4fc1e.gif戳“在看ce4108f8782e76e73fcdf6dceac7dc7e.gif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

有态度的马甲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值