• 单元测试是什么?怎么写?主要测试什么?


    1、什么是单元测试

    单元测试是开发者编写的一小段代码,用于检验被测代码的一个很小的、很明确的功能是否正确。通常而言,一个单元测试是用于判断某个特定条件(或者场景)下某个特定函数的行为。例如,你可能把一个很大的值放入一个有序list 中去,然后确认该值出现在list 的尾部。或者,你可能会从字符串中删除匹配某种模式的字符,然后确认字符串确实不再包含这些字符了。

    执行单元测试,是为了证明某段代码的行为确实和开发者所期望的一致。

    对于客户或最终使用者而言,这种测试必要吗,它与验收测试有关吗?这个问题仍然很难回答。事实上,我们在此并不关心整个产品的确认、验证和正确性等等;甚至此时,我们都不去关心性能方面的问题。我们所要做的一切就是要证明代码的行为和我们的期望一致。因此,我们所要测试的是规模很小的、非常独立的功能片断。通过对所有单独部分的行为建立起信心,确信它们都和我们的期望一致;然后,我们才能开始组装和测试整个系统。

    毕竟,要是我们对手上正在写的代码的行为是否和我们的期望一致都没把握,那么其他形式的测试也都只能是浪费时间而已。在单元测试之后,你还需要其他形式的测试,有可能是更正规的测试,那一切就都要看环境的需要来决定了。总之,做测试如同做善事,总是要从家(代码最基本的正确性)开始。

    2、为什么要使用单元测试

    单元测试不但会使你的工作完成得更轻松,而且会令你的设计变得更好,甚至大大减少你花在调试上面的时间。

    在我们上面的小故事里面,Pat 因为假设底层的代码是正确无误地而卷入麻烦之中,先是高层代码中使用了底层代码;然后这些高层代码又被更高层的代码所使用,如此往复。在对这些代码的行为没有任何信心的前提下,Pat 等于是在假设上面用竖立卡片堆砌了一间房子——只要将下面卡片轻轻移动,整间房子就会轰然倒塌。

    当基本的底层代码不再可靠时,那么必需的改动就无法只局限在底层。虽然你可以修正底层的问题,但是这些对底层代码的修改必然会影响到高层代码,于是高层代码也连带地需要修改;以此递推,就很可能会动到更高层的代码。于是,一个对底层代码的修正,可能会导致对几乎所有代码的一连串改动,从而使修改越来越多,也越来越复杂。于是,整间由卡片堆成的房子就由此倒塌,从而使整个项目也以失败告终。

    Pat 总是说:“这怎么可能呢?”或者“我实在想不明白为什么会这样”。如果你发现自己有时候也会有这种想法,那么这通常是你对自己的代码还缺乏足够信心的表现——你并不能确认哪些是工作正常的而哪些不是。

    为了获得Dale 所具有的那种对代码的信心,你需要“询问”代码究竟做了什么,并检查所产生的结果是否确实和你所期望的一致。

    这个简单的想法描述了单元测试的核心内涵:这个简单有效的技术就是为了令代码变得更加完美。

    3、我需要做什么

    引入单元测试是很简单的,因为它本身就充满了乐趣。然而在项目交付的时候,我们给客户和最终用户的仍然是产品代码,而不包含单元测试的代码;因此,我们必须对单元测试的目的有个充分的认识。首先也是最重要的,使用单元测试是为了使你的工作——以及你队友的工作——完成得更加轻松。

    4、它的行为和我的期望一致吗?

    最根本的,你需要回答下面这个问题:“这段代码达到我的目的了吗?”也许就需求而言,代码所做的是错误的事情,但那是另外一个问题了。你要的是代码向你证明它所做的就是你所期望的。

    5、它的行为一直和我的期望一致吗?

    许多开发者说他们只编写一个测试。也就是让所有代码从头到尾跑一次,只测试代码的一条正确执行路径,只要这样走一遍下来没有问题,测试也就算是完成了。

    但是,现实生活当然不会这么事事顺心,事情也不总是那么美好:代码会抛出异常,硬盘会没有剩余空间,网络会掉线,缓冲区会溢出等——而我们写的代码也会出现bug。这就是软件开发的“工程”部分。就“工程”而言,土木工程师在设计一座桥梁的时候,必须考虑桥梁的负载、强风的影响、地震、洪水等等。电子工程师要考虑频率漂移、电压尖峰、噪音,甚至这些同时出现时所带来的问题。

    你不能这样来测试一座桥梁:在风和日丽的某一天,仅让一辆车顺利地开过这座桥。显然,这种测试对于桥梁测试来说是远远不够的。类似地,在测试某段代码的行为是否和你的期望一致时,你需要确认:在任何情况下,这段代码是否都和你的期望一致;譬如在风很大、参数很可疑、硬盘没有剩余空间、网络掉线的时候。

    6、我可以依赖单元测试吗?

    不能依赖的代码是没有多大用处的。但更糟糕的是,那些你自认为可以信赖的代码(但是结果证明这些代码是有bug 的)有时候也会让你花很多时间在跟踪和调试上面。显然,几乎没有项目可以允许你在这上面浪费太多的时间,因此无论如何,你都要避免这种“前进一步,后退两步”的开发方法。也就是说,要让开发过程保持稳定的步伐前进。

    没人能够写出完美无缺的代码;但是这并没有关系——只要你知道问题的所在就足够了。许多大型软件项目的失败,诸如只能把坏了的太空船搁浅在遥远的行星,或者在飞行的途中就爆炸了,都能通过认知软件的限制来避免。例如,Arianne 5 号火箭软件重用了来自于之前一个火箭项目的一个程序库,而这个程序库并不能处理新火箭的飞行高度(比原来火箭要高)(引入单元测试是很简单的,因为它本身就充满了乐趣。然而在项目交付的时候,我们给客户和最终用户的仍然是产品代码,而不包含单元测试的代码;因此,我们必须对单元测试的目的有个充分的认识。首先也是最重要的,使用单元测试是为了使你的工作——以及你队友的工作——完成得更加轻松。),从而在起飞40 秒之后就发生了爆炸,导致5 亿美元的损失。

    显然,我们希望能够依赖于所编写的代码,并且清楚地知道这些代码的功能和约束。

    例如,假设你写了一个反转数值序列的方法。在测试的过程中,你也许会传一个空序列给这个程序——但导致了程序崩溃。实际上,程序并没有要求该程序必须能够接收一个空序列,因此你可以只在方法的注释中说明这个约束:如果传递一个空序列给这个方法,那么这个方法将会抛出一个异常。现在你马上就知道了该代码的约束,从而也就不需要用其他很麻烦的方法来解决这个问题(因为在某些地点要解决这个问题并不方便,比如在高空大气层中)。

    7、单元测试说明我的意图了吗?

    对于单元测试而言,一个最让人高兴的意外收获就是它能够帮助你充分理解代码的用法。从效果上而言,单元测试就像是能执行的文档,说明了在你用各种条件调用代码时,你所能期望这段代码完成的功能。

    项目成员能够通过查看单元测试来找到如何使用你所写代码的例子。如果他偶然发现了一个你没有考虑到的测试用例,那么他也可以很快地知道这个事实:你的代码可能并不支持这个用例。

    显然,在正确性方面,可执行的文档有它的优势。与普通的文档不同的是,单元测试不会出现与代码不一致的情况(当然,除非你选择不运行这些测试)。

    8、如何进行单元测试

    单元测试本来就是一项简单易学的技术;但是如果能够遵循一些指导性原则(guideline)和基本步骤,那么学习将会变得更加容易和有效。

    首先要考虑的是在编写这些测试方法之前,如何测试那些可疑的方法。有了这样一个大概的想法之后,你将可以在编写实现代码的时候,或者之前,编写测试代码本身。

    下一步,你需要运行测试本身,或者同时运行系统模块的所有其他测试,甚至运行整个系统的测试,前提是这些测试运行起来相对比较快。在此,我们要确保所有的测试都能够通过,而不只是新写的测试能够通过;这一点是非常重要的。也就是说,在保证不引入直接bug 的同时,你也要保证不会给其他的测试带来破坏。

    在这个测试过程中,我们须要确认每个测试究竟是通过了还是失败了——但这并不意味着你或者其他倒霉的人须要查看每个输出,然后才决定这些代码是正确的还是错误的。在此,你慢慢地就会养成一个习惯:只要用眼睛瞄一下测试结果,就可以马上知道所有代码是否都是正确的,或者哪些代码是有问题的。关于这个问题,我们将留在讨论如何使用单元测试框架时来具体讨论

    最后:下面是配套学习资料,对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!【100%无套路免费领取】

    软件测试面试小程序

    被百万人刷爆的软件测试题库!!!谁用谁知道!!!全网最全面试刷题小程序,手机就可以刷题,地铁上公交上,卷起来!

    涵盖以下这些面试题板块:

    1、软件测试基础理论 ,2、web,app,接口功能测试 ,3、网络 ,4、数据库 ,5、linux

    6、web,app,接口自动化 ,7、性能测试 ,8、编程基础,9、hr面试题 ,10、开放性测试题,11、安全测试,12、计算机基础

      全套资料获取方式:点击下方小卡片自行领取即可

  • 相关阅读:
    胆囊结石的后果
    Ae 效果:CC Ripple Pulse
    Springboot+swagger2
    会议OA项目(待开会议&所有会议)
    231022|推荐系统1-推荐框架注释
    IOT 围炉札记
    day076:枚举
    一文了解io包中的discard类型
    算法入门教程(五、贪心)
    【单元测试】--测试驱动开发(TDD)
  • 原文地址:https://blog.csdn.net/weixin_47648853/article/details/133858018