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

不会,单元测试,程序员,不是,一个,合格,滴滴,司机 · 浏览次数 : 440

小编点评

## Go unit test code with asynchronous write logging This code showcases a basic unit testing approach with asynchronous write logging using the `logrus` library. **Package structure:** ```go pkg/ mypackage/ main.go test/ writeLog.go ``` **`writeLog.go`:** ```go package mypackage import ( "testing" "github.com/sirupsen/logrus" ) func TestWriteLog(t *testing.T) { // Create a new logger l := logrus.New() // Set formatter with timestamp disabled l.SetFormatter(&logrus.TextFormatter{DisableTimestamp: true}) // Set output to discard all logs l.SetOutput(io.Discard) // Send a test log entry l.Info("test + time.Now()") // Run the benchmark function BenchmarkFire(t) } // BenchmarkFire function with 8 threads and 1s duration func BenchmarkFire(b *testing.B) { // Create a new log file for each iteration w := &logrus.Writer{ // Set output to a buffered writer Writer: &logrus.WriterBuffer{ Output: &w, }, // Set formatter with timestamp disabled Formatter: &logrus.TextFormatter{DisableTimestamp: true}, } // Start a timer for each iteration timer := time.NewTimer(1 * time.Second) defer timer.Stop() // Start writing logs to the buffered writer w.Info("test2") w.Warn("test3") w.Error("test4") // Wait for the timer to expire timer.Wait() } ``` **Explanation:** * The `writeLog.go` file contains the unit test and `BenchmarkFire` function for benchmarking. * The `TestWriteLog` function creates a new logger, sets its formatter to disable timestamps, and sets its output to discard logs. * The `BenchmarkFire` function uses a `logrus.WriterBuffer` to create a new log file for each iteration. * It sets up a timer to start and stop logging and starts writing logs to the buffer. * It waits for the timer to expire and then reports the test result. **Running the tests:** ```bash go test -run=writeLog_defaultfunc ExampleHook_default() ``` This command will execute the `writeLog.go` file with the `writeLog_defaultfunc` and `ExampleHook_default` functions, which are the default implementations used by the `TestWriteLog` function. **Output:** The code will print the following output, indicating successful test execution: ``` test2 INFO:test + time.Now() test2 test3 WARNING:test3 test3 test4 ERROR:test4 test4 ``` **Comparison with synchronous write logging:** The provided code also includes a basic comparison with the synchronous write logging implementation. The benchmark shows that the asynchronous version is around 10s+ faster than the synchronous version. **Note:** * This code requires the `logrus` library to be installed. * The `BenchmarkFire` function is a simplified example and may need to be modified for specific use cases. * The benchmark focuses on the performance of writing logs and assumes the logs are written to a file. For actual scenarios, the behavior may differ.

正文

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次对象。

与不会写单元测试的程序员不是一个合格的滴滴司机相似的内容:

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

go内置了一套单元测试机制: 利用` go test测试命令`和一套按照约定发方式编写的测试函数。 在包目录内,所有以_test.go为后缀名编写的go文件不会参与go build的编译过程. > 本文所有的代码均放置了[带缓冲区的异步写日志库](https://github.com/zwbdzb/

在C#中进行单元测试

单元测试 前言 时隔多个月,终于抽空学习了点新知识,那么这次来记录一下C#怎么进行单元测试,单元测试是做什么的。 我相信大部分刚毕业的都很疑惑单元测试是干什么的?在小厂实习了6个月后,我发现每天除了写CRUD就是写CRUD,几乎用不到单元测试。写完一个功能直接上手去测,当然这只是我个人感受,仅供参考

简单进行Springboot Beans归属模块单元的统计分析方法

简单进行Springboot Beans归属模块单元的统计分析方法 背景 基于Springboot的产品变的复杂之后 启动速度会越来越慢. 公司同事得出一个结论. beans 数量过多会导致启动速度逐渐变慢. 之前同事写过功能进行分析. 但是本着能不影响产品就不影响产品. 我想通过其他方式进行处理.

5.9 汇编语言:浮点数操作指令

浮点运算单元是从80486处理器开始才被集成到CPU中的,该运算单元被称为FPU浮点运算模块,FPU不使用CPU中的通用寄存器,其有自己的一套寄存器,被称为浮点数寄存器栈,FPU将浮点数从内存中加载到寄存器栈中,完成计算后在回写到内存中。FPU有8个可独立寻址的80位寄存器,分别名为`R0-R7`他们以堆栈的形式组织在一起,栈顶由FPU状态字中的一个名为TOP的域组成,对寄存器的引用都是相对于栈顶

洛谷官方题单--线段树

前言 发现线段树根本不会写,所以想要完成洛谷官方题单来稍微提升一下... 持续更新ing [ ] P3870 [TJOI2009] 开关 明确了写线段树要思考的几个点 1.如何update,即如何合并子节点的信息,这里就是直接将子节点的灯的数量相加即可 2.如何modify,即如何根据tag修改该节

正则表达式总结-1

转载 正则表达式真的很强,可惜你不会写 正则表达式是一种强大的文本处理工具,它允许你根据一定的规则来搜索、匹配、替换和验证文本,适配各种编程语言。 应用场景 正则表达式在计算机领域有广泛的应用,包括: 1、文本搜索和匹配:查找特定模式的字符串,如搜索包含特定关键词的文档。 2、数据验证:验证用户输入

第138篇:了解HTTP协议(TCP/IP协议,DNS域名解析,浏览器缓存)

好家伙,发现自己的网络知识十分匮乏,赶紧补一下 这里先举个我生活中的例子 欸,作业不会写了,上网搜一下 用edge浏览器上bing必应搜一下(百度广告太多了,真不想用百度举例子) 假设这是我们第一次访问bing的首页 当我向浏览器中输入https://cn.bing.com/并按下回车 浏览器做了什

【WPF】根据选项值显示不同的编辑控件(使用DataTemplateSelector)

接了一个小杂毛项目,大概情形是这样的:ZWT先生开的店是卖拆片机的,Z先生不仅卖机器,还贴心地提供一项服务:可以根据顾客需要修改两个电机的转向和转速(机器厂家有给SDK的,但Z自己不会写程序)。厂家有配套一个调节器,调整参数时连接到拆片机的串口上,然后旋转按钮可以调速,拨码开关可以设定电机正转还是反

SQL Thinking

s2下半年我在内部有一次部门级别的技术分享会,以本文内容分享为主。 其实有很多人问过我相同的问题,遇到需要改写的慢sql,不知道怎么改,改好了以后也不知道等不等价?不等价了也不知道错在哪?这个要怎么破? 其实都是因为绝大多数人没有做过开发,看不懂sql,不会写sql,没有sql思维,下面通过几个案例

[转帖]连shell的基本输出都不会,还写什么脚本?echo和printf命令总结

https://zhuanlan.zhihu.com/p/438957797 在 Linux 系统中使用 echo 命令和 printf 命令都可以实现信息的输出功能,下面我们分别看这两个命令的应用案例。 echo 1.使用 echo 命令创建一个脚本文件菜单功能描述:echo 命令主要用来显示字符