• 0
  • 0
分享
  • Go-单元测试详解与代码——软件测试圈
  • TIMI 2021-07-23 10:37:57 字数 3354 阅读 1259 收藏 0

概述

常言道,不会测试的程序猿不是好的产品经理!!!现在越来越多测试和运维的工作也需要研发来做了,本篇文章就来讲讲Go的单元测试。

单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。简单说,就是将测试用例的运行结果与预期结果进行比较。

Go的单元测试

基础知识

Go有testing测试包,配合go test命令能够进行单元测试。

  1. 测试文件以_test.go结尾

  2. 在包目录内,所有以_test.go为后缀名的源代码文件都是go test测试的一部分,不会被go build编译到最终的可执行文件中。

  3. _test.go文件包含TestXxx函数

  4. 形参类型必须为*test.T

  5. PASS表示测试用例运行成功,FAIL表示失败

个人常用Fatalf,这里就来具体说一下,其他函数见参考的链接。

func (c *T) Logf(format string, args ...interface{})

Log 使用与 Printf 相同的格式化语法对它的参数进行格式化,然后将格式化后的文本记录到错误日志里面。 如果输入的格式化文本最末尾没有出现新行,那么将一个新行添加到格式化后的文本末尾。

  1. 对于测试来说,Logf 产生的格式化文本只会在测试失败或者设置了 -test.v 标志的情况下被打印出来;

  2. 对于基准测试来说,为了避免 -test.v 标志的值对测试的性能产生影响,Logf 产生的格式化文本总会被打印出来。

func (c *T) FailNow()

将当前测试标识为失败并停止执行该测试,在此之后,测试过程将在下一个测试或者下一个基准测试中继续。

FailNow 必须在运行测试函数或者基准测试函数的 goroutine 中调用,而不能在测试期间创建的 goroutine 中调用。调用 FailNow 不会导致其他 goroutine 停止。

func (c *T) Fatalf(format string, args ...interface{})

调用 Fatalf 相当于在调用 Logf 之后调用 FailNow 。 

快速入门

项目结构

learnGo

└── main

    ├── compute.go

    └── compute_test.go

compute.go

package main
 
import "errors"
 
func div(a,b int) (int,error) {
if b != 0{
return a/b,nil
} else{
return 0,errors.New("b is 0")
}
}

compute_test.go

package main
 
import "testing"
 
func TestDiv(t *testing.T)  {
res,_ := div(4,2)
want := 2
if res != want{
t.Fatalf("期待:%d ,实际结果:%d",want,res)
}
}

main目录下运行

go test -v

结果如下:

=== RUN   TestDiv
--- PASS: TestDiv (0.00s)
PASS
ok      learnGo/main    0.457s

以上我们就针对main包的compute.go文件进行了单元测试。

进阶

查看更多的选项,可使用

go help test
 
go help testflag

单个文件的测试

我们在main包中再添加str.go及str_test.go

str.go

package main
 
func getSub(str string,start,end int) string {
// 左闭右闭
if 0<=start&&start<end&&end<=len(str){
return str[start:end]
}else{
return ""
}
}

str_test.go

package main
 
import "testing"
 
func TestGetSub(t *testing.T)  {
astr := "lady_killer9"
// 包含开头
res1 := getSub(astr,0,4)
want1 := "lady"
// 包含结尾
res2 := getSub(astr,4,len(astr))
want2 := "_killer9"
// 范围错误
res3 := getSub(astr,1,len(astr)+1)
want3 := ""
if res1 != want1{
t.Errorf("期望:%s,实际结果:%s",want1,res1)
}
if res2 != want2{
t.Errorf("期望:%s,实际结果:%s",want2,res2)
}
if res3 != want3{
t.Errorf("期望:%s,实际结果:%s",want3,res3)
}
}

运行 go test -v,得到结果如下

=== RUN   TestDiv
--- PASS: TestDiv (0.00s)
=== RUN   TestGetSub
--- PASS: TestGetSub (0.00s)
PASS
ok      learnGo/main    0.446s

go test会运行所有的单元测试,有时候我们只想测试某个文件

如果只是运行一个测试文件,可添加参数

go test -v 测试文件 源文件

运行go test -v str_test.go str.go, 结果如下:

=== RUN   TestGetSub
--- PASS: TestGetSub (0.00s)
PASS
ok      command-line-arguments  0.619s

单个函数的测试

我们在compute.go中添加

func add(a,b int) int {
return a+b
}

在compute_test.go中添加

func TestAdd(t *testing.T)  {
a,b:=3,4
res := add(a,b)
want := 7
if res != want{
t.Fatalf("期待:%d,实际结果:%d",want,res)
}
}

由于对div函数未做改动,只想测试add函数,可以使用参数-test.run指定测试函数

go test -v -test.run 测试函数

运行 go test -v -test.run TestAdd 结果如下:

=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
PASS
ok      learnGo/main    0.836s

单元测试覆盖率

测试应该全面,达到100%。

可以使用-cover参数

go test -cover

结果如下:

PASS
coverage: 85.7% of statements
ok      learnGo/main    0.505s

可以看到,测试的并不全面,指定测试文件来查看。

go test -cover compute_test.go compute.go
ok      command-line-arguments  0.314s  coverage: 75.0% of statements

观察发现,我们缺少了b为0的分支,修改TestDiv函数为

func TestDiv(t *testing.T)  {
res,_ := div(4,2)
want := 2
if res != want{
t.Fatalf("期待:%d,实际结果:%d",want,res)
}
res,_ = div(3,0)
want = 0
if res != want{
t.Fatalf("期待:%d,实际结果:%d",want,res)
}
}

测试后再看覆盖率,结果如下

PASS
coverage: 100.0% of statements
ok      learnGo/main    0.306s

作为开发,基本的单元测试就可以了,还可以去了解基准测试、性能测试、压力测试、黑盒测试等。


作者:lady_killer9

原文链接:https://blog.csdn.net/lady_killer9/article/details/116139322

  • 【留下美好印记】
    赞赏支持
登录 后发表评论
+ 关注

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          •   随着科技的发展和进步,自动化测试的应用越来越广泛深入,作为一种软件质量管控的重要手段,自动化测试通过将人为驱动的测试行为转为机器执行的一种过程。在替代大量重复性工作和提高回归测试效率方面发挥了很大的优势。  目前,自动化测试还不能完全的取代人工测试,自动化测试是否能够有效开展依赖于系统的稳定性。对于投产周期短,需求变更频繁,版本更新频率较高,甚至存在系统架构重构的可能性的系统,使用自动化测试工具录制的案例,在系统迭代更新后,需要频繁的修改调试自动化脚本,成本较高,因此此类系统不适用于自动化测试;对于部分优化升级系统,系统架构都趋于稳定,程序版本稳定,特别是投产周期长,需要频繁重复执行测试案...
            15 14 743
            分享
          •   前言  通常在接口自动化中,经常会参数关联的问题,那么什么是参数关联?  参数关联就是上一个接口的返回值会被下一个接口当做参数运用,其中Python中可以实现参数关联的方法有很多种,今天小编给大家介绍下,如何通过Python来实现接口自动化中的参数关联。  UnitTest  虽然说目前Pytest框架比较流向,但是目前应该有绝大部分公司还是在使用UnitTest框架,那么小编先介绍下如何通过UnitTest来实现接口自动化的参数关联。  方法一  下面小编通过测试用例返回参数的形式进行实现参数关联。# coding:utf-8 import requests impo...
            0 0 967
            分享
          •   一.背景介绍  继自动提交bug到jira文章之后,这时候就会有人有疑问了,我每天都在跑自动化测试(美其名曰每日构建),也每天都在自动提交bug,可能昨天提交的bug尚未解决,今天又重新提了一遍,一周下来累计的bug好几千了,怎么办?一个个去手动过滤,有木有感觉直接崩溃了?那么为了解决这个问题,今天我们就来介绍一个自动化过滤的方案及其实践。  二.测试需求分析  此方案也主要使用python/pytest实现,主要针对于jira上bug的处理,当然也可以使用过滤重复需求,重复任务等等均可以。  准备工作:  1.在处理之前,你首先需要了解部门的jira流转图(不同公司或部门都可能不一样),...
            0 0 653
            分享
          •   1、引言  在撸码过程中,99.1%的大佬,都不敢说自己的撸出来的代码,是不需要debug的。换句话说,码农在撸码过程中,最痛苦的,莫过于撸出来的代码,为了能避坑,小鱼也是在撸码过程中,总结的一点避坑方法,请各位大佬笑纳。  2、避坑内容总结  2.1无法定位到元素  遇到问题:  找不到元素,脚本报“NoSuchElementException:Unable to find element”,或"定位到了,不能操作,点击无效。  解决方法:  1)查看自己的“属性值”是否写正确  2)元素的标签不唯一,默认找到第一个  3)向上查看,元素是否在frame或iframe框架中  ...
            0 0 794
            分享
          • 写在前面:这是我第一次参加实习面试,面试前也在网上查了一下算法岗面试的相关经验,受益颇大,因此自己面试完后也试着记录了一下,虽然没能通过最终面试,但也希望能给想面试相关岗位的人一些启发和帮助~关于面试准备:算法的技术面主要考察的是算法的灵活使用和现场编程能力,以及相关方向的模型(基本上就是统计机器学习、自然语言处理、计算机视觉这些),因此主要准备以下两个方面:经典的算法题目;复习各种常用的模型,特别简历写的项目中使用到的。一面:项目介绍和模型知识考察对简历上的一个项目进行介绍?(接下来是根据我项目和我说话中提到的模型,开始深入地追问)SVM模型的介绍LR模型的loss函数是啥?为什么选择它作为...
            0 0 1423
            分享
      • 51testing软件测试圈微信