00:00
那既然这个单元测试这个问题已经分析出来了,那下面呢,我们就来直接说这个单元测试了,各位同学看一下。那go语言中呢?自带一个轻量级的测试框架,叫testing。和自带GOT的命令来实现单元测试和性能测试,注意啊,它既可以做单元测试,同时呢,它也可以做性能测试。那怎么说体现出性能测试呢?性能测试其中一个最主要的参考指标就是时间。就说我执行你这个代码,我花多少时间是不是?诶如果说我们这个它本身能够把这个函数测试的时间返回来,那不是更方便吗?尤其是在我们生产环境,我们想去测一个函数,它运行的效率,速度怎速度怎么样,诶这样就非常方便,那么test视频框架和其他语言的框架类似,可以基于这个框架写针对于相应函数的测试用例。测试用例呢,我们经常叫这个词叫test case,或者叫testing case case就是一个测试用例,也就是说我们将来呢,测一个函数,或者说测一个函数,或者说测一个模块呢,我们通常把它叫测试用例这个概念也可以基于该框架写相应的压力测试用例啊,通过单元测试呢,可以解决如下问题,第一个确保每个函数是可运行的,并且正确,第二点,确保我们写出的代码性能是好的。
01:26
你千万不要写了一个代码是吧,张三写个代码,李四写的代码,你想知道谁的代码更好,直接用这个test一下就测试出来了。啊,一下就特殊出来了,那么单元测试能及时的发现程序设计中实现的逻辑错误。就说我希望一个值,但是你返回的不是对的,好,逻辑错误让这个问题及早暴露,便于定位解决。而性能测试呢,重点在于发现程序上设计的问题,让程序能够在高并发的情况下还能保持稳定好,这是它的一个基本介绍啊,那么一会儿呢,我们就开始上他的具体案例,来把这一段给大家板述一下。
02:07
这是单元测试的一个基本介绍。那我把刚才的内容呢,进行一个板书,就是以后呢,同学们就不需要看这个幻灯片了,所有的内容呢,都在这一个笔记里边,对吧?啊OK。好,刚才老师已经讲了啊,我们再说一下,第一个能确保每个函数是可运行结果正确,这是第一点,刚才老师说的这一点,第二点呢,我说了保证我们的性能是好的。啊,这点很重要啊,如果说你将来想去看你的下面的手下,比如说你你下面管了十个程序员,哎,你想看看哪个程序员到底是真干活还是假干活呢?简单你把这个测试用一测,发现人家写代码一写写代码对吧,要么是错的,要么性能性能很差啊,这个时候一下就把这些抓出来了啊,然后呢,还可以发现我们的逻辑错误。啊,还可以让我们的性能性能测试啊,非常方便,好各位同学,基于这些原因呢,我们来继续往下看。
03:08
那这个说完了过后呢,我们就直接来一个快速入门对吧,我们不废话了,那现在呢,我们现在直接用go的单元测试。来对I的up和S函数,这个S函数我没有写,待会我加一个,就是求两个数的差进行一个测试啊,我这里做一个特别说明啊,这地方有个温馨提示,就说有些时候你们在测试的时候呢,就在你们机器上测试的时候,可能需要暂时退一下360。因为360呢,有可能会认为生成的测试用力是个木马,但实际上我们不是木马啊,有可能哈,如果你出现这个情况你就退,但如果没有出现就算了,因为它这个360有时候呃,在不同系统下,它也不一样,跟你那个运行的时间也是有有关系的,反正这块呢,跟跟它底层是有关系的啊好,现在我不说废话,我们来马上的测一下。
04:00
来,走单元测试的快速入门,入门完了我们再讲细节,好吧,各位同学。好,现在呢,我们要做的事情是这样子的,来,跟着老师的思路动起来。好,特别说明这事实。好,现在呢,我们来给大家演示如何测试,演示一下。演示如何进行单元测试,各位如何进行单元测试?好的,我把它做一个出的标题来吧,打开我们Vs code,我们就做刚才这个事情,各位朋友我们就说这个事。我们就做这个事儿啊,好好的保存100,诶保存100,保存100的话呢,各位同学这个时候。这为什么错了啊,他说没有用到这个主函数,我们先暂时的先把它不要了啊,郭同学我不要了啊,当然后面再恢复也可以,无所谓,好这个写写到这儿,写到这个地方呢,大家看到他报这这个地方,因为没用嘛,所以说先不用用它。好。
05:01
OK,那这个时候呢,我们就来开始做这样一些工作了,首先我先把这个组的点构,呃,换一个别的名字,我为什么要把它换一个别的名字呢?呃,因为你你这个函数将来说实话,你测试的函数不会直接放在面点勾对不对,大家想一想,我们前面讲了这么久,我们是不是将来会把自己的函数写到一个专门的一个UT下面去啊,所以说我这样写好不好,我这样写了啊同学们,然后就我我我干脆就不动它,我不动它啊,我不动它。呃,这个地方因为没有把它保留在这也无所谓啊,给它留一个这个主主主函数接口也无所谓,因为我们我们真实测呢,我们可以实项说的,我们新建一个文件夹,好吧,我们新建一个文件,比如说我们这个test case,第一个我们第一个测试的用例,好我把刚才的那个文件这么玩一把,注意听啊,我新建一个文件叫KGO。那也就是说我将来呢,计算的关于计算的函数呢,我就直接怎么样能在这个包包里面去,这个没问题,好package主包。
06:08
没有问题,没有问题,然后呢,我这个地方把刚才写的这一个函数怎么样拿过来,因为这个函数呢,是我准备要去做测试的。好,这个就写到这了,写到这过后各位同学,写到这过后呢,我们现在呢,报错,报错的原因是因为它发现你这没有主函数对吧?没有主函数不要管它,紧接着写下一个函数。叫什么呢?叫做开了下划线test。注意啊,待会儿我们再讲,再讲规范。好,回撤。那回车过后呢,我们这里面写一个package,也是主包包。也是主播,然后这里面呢,我们来一个import。Import me,好,这个地方要这样写了啊,同学们写一个函数,编写一个函数啊,编写一个测试用例,变测试用例用例。
07:05
去干什么呢?去测试,去测试刚才写的这个函数是否正确。写这个函数是否正确?是否正确?怎么写这有规范了?同学们怎么写这有规范?那么我们先先给大家入门说说细节,我先不说啊,我先直接说。然然,前面命名必须是test。必须是test,然后呢,我们后面一般会写上你要测的这个函数的名字。啊,要测的这个函数的名字,那么这个地方这个A呢,我们要大写,待会儿再讲细节好的写完。写完写完过后,写完过后这边会有一个参数,各位这边会有个参数比较重要,这个参数呢是这样写的。好的,那待会我再解释啊,同学们待会讲,那既然用这呢,我们需要以一个包。
08:04
要用一个这个台式顶包。它不这个是干什么呢?这个是引入,相当于是引入我们这个GOGO的这个测试testing这个框架。框架这个包,轻量级这个框架的包,框架包好,讲到这呢,我们有必要给同学们看一下这个台台屏是什么,打开我们手册啊,打开我们手册。打开我们手册,我先给他定定一下位,你们看一下这个台词亭里面有哪些内容好不好,看一下有哪些哪些内容来。那现在呢,我们百度一把。找到我们go的官方文档,这个呢,大家都都应该很熟悉了。Go,官方。官方文档啊,官方文档OK,那现在呢,我们收到这个地方去,我们看一下testing这个包包,Test这个包呢,以T打头的,应该在屁股后边,我们发现有个testing。好,我们看看这个干什么的啊啊,Testing提供了对go包的自动测试化的支持,通过go test指令能够自动执行如下形式的任何函数,什么形式的呢?就是以test这个打图的各位。
09:13
太的后面这个叉叉叉随便写后面这个叉,但是有要求,其中哎,这个叉叉叉可以是任何字母,任何字母数字字串,但是第一个字母就这个玩意儿。不能是小写的A到Z,为什么?因为它是用于识别测试历程,历程就是我们所说的用例啊,历程一,一般这个台湾比较喜欢说,哎,我们叫城市,我们程序是吧,台湾人一般翻译成这是一个城市啊,那就比感觉很奇怪的样子,那么他语法呢,就这么简单,那现在写完我们来接着往下写,接着往下写好接着写我们来干什么呢?调用调用。调用哪一个函数呢?就调用这个res走测试我们的I的upper upper好传进去一个十。
10:07
传进一个式,然后呢,我就做一个测试,如果R不等于55,我们就认为它错了来呢。打印出这个错误信息啊,就说呃,就说我们叫做爱的upper,这个这个执行错误。啊,执行错误。执行错误。为什么执行错误呢?我们是期望。期望值等于多少,实际值实际值等于多少,来各位,那现在呢,我要做的一件事情就是把它输出来,好,当然这地方我应该格式化一下啊各位朋友。好,然后呢,我这边有一个换行,把它的值放到这里,我们期望是55,但你返回的是RE。好这样如果正确的话呢,诶这个地方同学们啊,我们就可以不用这样这样输了,以前是这样输,这次呢,咱们就换成用T来输。
11:02
T,它有一个特别好的函数叫fat fat就致命的,致命的,然后呢,这个地方我们写它一个输出L啊,应该是log吧,类似于这样一个方法啊,我们看一下是不是有一个这样的函数,打开看。嗯,这地方有一个这样的信息,就是T,我们来看这个T长什么样子啊,来找到testing。里面呢,它有一个类型,这个类型就是刚才带同学们看的这个类型叫T。OK,这个T我们点进去。Lawyer,大家看这个T呢,它是一个什么呀?结构体,这个结构体提供了很多的方法,其中有一个方法叫FF就格式化可以调用,它相当于在输出这个日志,输出这个日志的同时呢,它还把这个程序给停止了啊,这个人用的比较多,所以说我用这个发F。那我刚才这句话呢,就可以这样用了。
12:02
诶,我们用这这句话相当于说输出这个日志,然后退出,因为你这相当于说代码出错了吗?那如果没有退出怎么办呢?好,下面呢,我们就正常写日志,如果正确,那到这儿就正正确了啊,如果正确我们就记录日志。记录这个日志或者输出日志都可以啊,输出这个日志,这个日志怎么输呢?T有一个方法叫log。啊,我们就写一句话,就说什么什么执行执行正确。执行正确。好,执行正确好,代码就写完了,代码就写完了,那么我们现在呢,保存一下这个代码,看看能否正确。跑一下保存。保存过后呢,我们发现诶。哪里还有错误?哦,这是我说是不是小写的啊,各位同学,这个这个IAI的这个阿尔法,我是小写的对不对,我是小写的,好这样子再看一下有没有错误。
13:01
Format是不是因为没有用到,没有用到的话,是不是可以让他暂时的怎么样。注销了。好的,看看还有没有什么错误,我们发现没错了,大家可能会觉得,哎老师没有,好像没什么感觉啊,你这写的东西不就是相当于写了写了个构点,呃,写了一个I up,然后这写了一个一一个你你你把它叫做测试用例的这么一个东西吗?好像没有感觉,但是当我一一运行的时候,你会觉得很奇怪,至少你应该有个疑惑,大家看我怎么用啊,现在我还我还没讲细节,同学们看,现在已经出现这么一情况,这是你的一个他testing,这是一个用例,它已经可以去测试它了,他们之间的关系你可以这样理解,各位同学。我画一个非常重要的一个示意图啊,注意听这块呢,他们之间的关系,你可以这样理解,也可以这样理解,怎么理解呢。这这个地方是我们的一个。
14:02
这是我们写的一个叫开了。开了。C_test把这个我稍微把它放大一点,然后呢,然后这个里面呢,它们之间的关系。这有一个我们的一个文件,这两个文件他们是当倒底是有关系的啊,也有对应关系,写了个开点构,这里面有我们的函数,当然有可能有很多哈,呃,函数一函数二,当然有可能很多,函数一函数二,好,然后呢,我在这个地方。我在这个地方相当于是去对什么呢?对我们的这一个函数1GO的,注意听是开了点go的函数进行了一个测试。好,那这个时候呢,大家会看到啊,我们现在已经可以测试了。但是你们应该会感觉到很奇怪,说老师为什么可以测试,因为我你你你连主函数都没写,但是我一运行你会发现跑起来了,CD点点我回到这一节,注意看第二我进入到test这个功能,然后我怎么运行呢?看到现在我这边有俩文件,一个是开了点go,一个是开了test,现在我要运行它使用我们的哪一个呢?Go test_V回车。
15:20
各位,各位。360好像没有出来,非常的好,非常的好,大家可以看到我们这里有一个问题。他说。Run。Run。Test,他说你现在我帮你运行了一个叫test at up这么一个用例,或叫历程,那他说你这个错了啊,你这个错了,为什么错了呀?他说你这个是14行,他说你爱upper执行错误了七万五是五,但是实际上是一个45。写错了,而且他告诉你,他告诉你,你的这一个文件一共用了。这么多秒时间。
16:00
大家会觉大家看,也就是说实际上他已经帮我们调用了这个函数。但是你们应该会觉得很奇怪,诶,老师,主函数在哪去了呢?主函数到哪去了呢?各位,所以说老师要告诉大家,主函数其实是这样子的各位,因为我们地方其实是跑了一个可爱的test框架。也就是说,当你运行的时候,其实调用的是test这个框架。这个T这个框架呢,它有一个能力,它其实会将你这个以什么什么结尾的,就是它会干什么呢,注意听他会做两件事情,第一件将。将默认情况下将前面这个名字啊,不管你怎么写下划线test.go的文件引入。引入,那么相当于说你可以理解成这有个主函数能理解这意思吧,你可以这样简单理解说,主函数被它隐藏起来了,他把你的这个文件引入,引入过后呢,你这地方不是写了有这些这些这些个玩意儿吗?比如说你写了一个这样的东西。
17:06
这样一个函数。各位,你写了这样一个函数,OK,注意听。你写了这样一个函数。诶,我先我先放到这儿啊,诶。这,这怎么跑哪去了,跑哪去了啊,你写了这么一个函数。那你刚才不是写了那个函数吗?它就干什么呢,它因为它把你的所有的以这个呃什么什么下划线test的这样结尾的一个空键引进去,当然你可以理解成类似于有个音泡的,我我不去先那么详细了啊,因为它它是按照个规范来引的,引进去过后他就把你又接着第二步,这很重要。第二步,它也有规范,它将你以test这个打头的函数全部给你。掉下。但他为什么一他就开始调什么呢,调用。调用你的以这个test叉叉叉打头的。
18:02
的函数,就你这是按这个函数写的,我就给你调起来,于是乎同学们看到其实就这样子的,也说系统它会怎么做呢?我们的系统一运行,他就跑过来去玩你的这个东西了,他跑过来去执行你的这段代码。对,他会跑过来执行这个。好,他就直接直接执行你这个东西了,系统一定要用,它发现你这你的是一个test框架,它就调这个,调这个的时候呢,它这个里面test框架会把你的这些个,你这个呃,Test的点go结尾的这些文件引进去,然后他继续扫描你这个文件里面有哪些是以test打头函数在调,而你这里面又写的是把这函数调进去,所以说这个就一层一层的像这样子进行了一个简单的引入并操作,比如这样逻辑就变成这个了。什么东西呢,我。你被我引住。
19:00
你被你,你被我引入。啊,然后呢,这个可爱的这个test的文件呢,又被我引入。好,他们之间的关系就这样子的形成了一样,111个这样的一个调用关系,那是不是这样子的呢?完全是这样子的来,既然刚才韩老师说的,只要是以这个test的什么什么开头的,它都会被调用,那么再写一个文件,各位同学我们再写文件,看看跟韩老师讲的是不是一样的啊各位第一个我们来证明一下,首先。来,各位同学,我把这个函数名给我瞎改一个,你们看看能不能跑起来,各位朋友请看我把它改成一个。OK,来。这个时候,此时此刻这个函数已经不再适应开始的打头了,那么这个时候我们一运行,各位朋友请看代码。啥都没有。但是他还是跑了一下,他还是跑了一下,因为它本身这个框架执行是需要时间的,对不对?他说pass啥都没有,No tests to run什么意思。
20:08
没有一个用力测试去运行完事,因为你的函数已经跟人家写的不是这个规范了,你你写错了,好这是第一个,第二个我们来证,再来证明第二点,只要你有别的这个函数一样会调用啊,打个比方说韩老师说韩老师假设我这样写一个呢。我这样写一个呢,说老师假设我写的是这样一个玩意儿,它会不会也被调用呢?比如说我有个test。Test。别的啊,比如说我写了一个泰的哈。然后写呢,然后呢,我这就写了一句话,就说哈被调用,各位同学动动脑筋,你们觉得会不会调用呢。必须的啊,必须的,所以你就写个test哈,被调用被调用。被调用或者被测试对不对,被调用OK,那同学们看看,我们再运行一下,看这个家伙会不会也被扫描进去,因为刚才我已经讲了啊,诶这个报错了,报错的原因是因为我这里没有对吧,各位我没有这个。
21:11
那完蛋,这个是不是也没用啊,他说他说你没用这个。会不会报这个错呢?诶,他他怎么不报这个了。这个创建参数没有用,它不报错哈。啊,不不错是吧。那我运行一下,看看他报报报报不报错呢,好看看到啊,我两个都有了啊,这个时候你们看一下运行效果是什么样子的好。好。哦,各位同学请看这有点意思了,这有点意思了,你看第一个,他说你调用了一个这个用力是说的,他说你还调用了一个这个是吧。看到没有,所以这个是是是吧,这个是pass了,因为你因为你没有报那个filter吗?刚才说错误了,所以你看这两个被调用了,所以证明刚才我的观点是正确的,我们再测试第二个啊,我们待会再说细节,大家先跟着老师动起来,所说现在假设我们还有一个文件。
22:01
我们还有一个文件也是以这个打头的,比如说写了一个别的文件啊,打个比方,各位同学现在呢。韩老师又写了另外一段一段啊,比如说我在这里面,我在这里面呢,又干了一件事啊,Fun,我写了一个什么呢?Sub get啊,比如说呃,Get sub and啊就就写一个get sub吧,好吧,Get sub就是求两个数的什么呀,差就可以了,N1N2,注意听那返回一个值嘛,返回一个值,那么我们就这样返回return n1,呃,减掉一个N2完事。对吧,非常的简单,非常简单,但是呢,但是呢,这个时候我想干什么呢?呃,我想。这用为什么报错了?这个地方应该不。哎,没有没有主函数。这个不应该是吧。
23:02
啊,那么我看看啊。他说这个这有个主函数,他说没有主函数是不是。啊,这地方我保存,我全部保存。全部保存。啊,他说没有主函数,那我把它去掉,它也没主函数啊。哎,邪乎。你看没有。嘿嘿,同学们,我干啥事啥都没呢。诶,邪了,你看我刚才还好好的呢,我跑一下。我跑一下。其实不是事儿是吧,其实不是事儿。他这个是不是误报啊。
24:01
哦,我刚才把他删掉了吗,难道。我没有删掉啊,应该没事啊,应该没事,他他一会儿应该是没是没什么事啊,我先接着讲吧,我先接着讲啊,比如说我在这边还有一个函数,我还有一个函数啊,注意听我先写着get sub,刚才那个函数我先撤回去。啊,我求两个数的什么呀?求两个数的差,就是求两个数的差,求两个数的差,那么这个时候呢,我想把这个测试用例写到另外一个文件里面去,比如说我又写了一个新的一个一一个文件,比如说比如叫什么呢?S。叫S。下划线test.go啊test go,那么整个这个思路呢,跟前面是很类似的,所以说我把这个呢,粘贴复制一份过来啊粘贴复制一份过来,然后呢,我放在这个sub。T顶购里面去。好,那我怎么做呢?诶这个地方我们要测试的是另外一个,我要测试的是这这个我先不要。
25:05
这个我先不要了啊,我要测试的是哪一个呢?测试那个sub。注意后面这个名字啊,其实叫什么都无所谓,但是只只要你这个地方第一个字母不要以小写的A到Z打头就可以了啊啊这个地方我就要换一个名字了啊,叫改名,我们最好名字进行一个统一,叫get sub,但其实你这你这只要这个字母啊,只要不以A到Z打头,它都会掉。就跟刚才大家还记得有个哈吗?他不也吊起来了吗?好,这个我就换了啊,这个地方我叫get sub。Getup,好,我输入两个输进去,比如说一个是十,一个是三,我们期望如果它不等于七。因为十减去三,我们知道结果是七嘛,那我就注意这样一个测试,就说这个函数执行错误,我们期望是七。但实际上是几呢?实际上是RS。好,那么这个时候如果这没有报错,那就说正确,我们把这个输出来。
26:05
好,现在呢,我们来看看一下啊,同学们。现在我们来看一下这地方为什么错了啊,因为这个地方我们没有用它。好保存。保存。没有定义该sub。没有,弟该上。啊,我们先看看是是不是他非要写到单独的文件里面去啊,我先运行一下先,如果非要写到单独文件我们再说。先跑一下。跑下。好,我们现在看看这个时候的情况啊,这个很怪,有点怪啊,大家看第一个test upper,它说错误了,这个确实跟我们想的一样,它紧接着说这个哈,Test被调用,但是呢,这个是pass了,就说明成功,紧接着它帮我们运行的这个test getup,它这个呢,执行是正确的,其实代码。
27:03
都没问题,但是为什么他报一个这个错误,是编译器的问题吗?难道。哦,跟这个包名是必须要包名换一个是吧,换一个别的包名我试试看,我我我先把它保存保存,我先退一下啊,我退一下重新打开一下,其实面包应该也问题不大的。行,我们换一个吧,换一个包名,在刚才那个,呃,小曹说的这个呢,也是有道理的,换一个包名就行,换一个包名统一换一个包名就完了,也不是大事啊。好,我们来看看现在打开过后有没有报错。打开锅有没有报错还是报错,那就换一个名字吧,比如说我们叫做什么包呢?开了对吧,开了这个包,那下面这个时候我们都把统一换一个包包。开了好这边呢,也把它换成开了。好,整个保存。
28:00
好,整个保存。好,整个保存过后呢,我们再来运行一下啊哦,为了看到有有这个有这个变化呢,我们把这个呃稍微的改一改,比如执行正确,这样后面我多打几个叹号,表明这个我们做了修改,OK,跑一下。跑起来。跑起来好,我们可以看到这个时候呢,他的确输出了最新的这个叫这个,而且大家有没有发现它有个有点意思啊,他在这个测试的时候呢,他会把你这边设置的所有的用力全跑起来,然后呢,整整个到底是成功了还是失败了,看这就说他先对你每个用力都跑一下,但是只要有一个错,它就认为是错的,那如果说都正确才是正确的啊,那我把这个改对,比如说这个开了里面呢,它这地方我们本本身代码就写错了,我把它写成正确的。好,如果我把写成正确的各位朋友,我们再跑一下,跑起来我们发现完全OK。啊,这个时候就整体全部正确,你看这个是pass,这个是pass,这个也是pass,每一个用力花的时间也是出来的,啊看第一个用力花了0.0秒,就因为太小了嘛,这个花了0.01秒,说明大家看到没有,大家说明这个这个函数调用还是很费时间的,就这个函数还是很费时间的。
29:23
啊,然后呢,嗯,这个是0.0秒,整体用了2.168秒,为什么这个时间加起来跟它不一样呢。为什么这个时间是2.16秒,而这三个用力加起来还不到一秒呢?原因各位朋友,你加载这个框架是需要时间的,你框架。你你这个框架实际要排出去,说这个逻辑就这样子的啊各位,那关于它的一个基本介绍,就说这那么下面呢,我们这整理了有关于入门的有这11个细节,这11个细节讲完了同学们就彻底的。就说用这个框架就没问题了,好,关于前面这个基本介绍呢,我们先板述一下啊,板述一下OK,那么我们怎么玩的,我们怎么玩的呢?呃,那就干脆直接把这个粘过来就可以了,为什么?因为是一样的啊,因为是一样的,我先把这块给各位板说到这里,板说到这里,然后呢,这这个地方我们就把这个单元测试的快速入门给大家伙讲清楚了,包括它的一个原理图,就是单元。
30:27
单元测试的原理啊,运行原理啊,运行原理示意图。对不对示意图。那么这个示意图呢,也很重要,就是你把这个示意图搞懂了,各位朋友,那也就说底层的原理你你是清楚的,他们之间的关系你就搞清楚了,来,我先把它给同学们保存到咱们的笔记里边去,OK。好,截取一段视频。
我来说两句