第三讲-如何做好单元测试

如何做好单元测试

必备技能:
1、代码的基本特征;
2、产生错误的原因;
3、单元测试的基本方法和主要技术手段,如什么事驱动代码、桩代码和Mock代码

第一,代码的基本特征与产生错误的原因

代码是有规律可寻的,由条件分支、循环处理和函数调用等最基本的逻辑控制。

要做到代码功能逻辑正确,必须做到分类正确并且完备无遗漏,同事每个分类的处理逻辑必须正确。

开发为了设计并实现逻辑正确的代码,通常会有如下的考虑:
1、要实现正确的功能逻辑,有几种正常的输入;
2、是否有需要特殊处理的多种边界输入;
3、各种潜在非法输入的可能性以及如何处理。

第二、单元测试用例详解

单元测试的用例是一个“输入数据”和“预计输出”的集合
完整的“输入数据”:

  • 被测函数的输入参数;
  • 被测函数内部需要读取的全局静态变量;
  • 被测函数内部需要读取的成员变量;
  • 函数内部调用子函数获得的数据;
  • 函数内部调用子函数改写的数据;
  • 嵌入式系统中,在中断调用时改写的数据;
    。。。。
    如果没有明确的预计输出,测试本身就失去来意义。“预计输入”绝对不是只有函数返回值这么简单,应包含函数执行完成后所改写的所有数据。
  • 被测函数的返回值;
  • 被测函数的输入参数;
  • 被测函数所改写的成员变量;
  • 被测函数所改写的全局变量;
  • 被测函数中进行的文件更新;
  • 被测函数中进行的数据库更新;
  • 被测函数中进行的消息队列更新;
    。。。。
    对于预计输出值,必须严格根据代码的功能逻辑来设定,而不能通过阅读代码来推算预期输出。
    如果某些等价类或边界值,开发没有考虑,测试的时候不会设计测试用例,会造成测试盲区。
第三、驱动代码、桩代码和Mock 代码

驱动代码是用来调用被测函数的,而桩代码和Mock代码是用来代替被测函数调用的真实代码的。


13191251-55d225dfb5af3c97.png
三者逻辑关系

驱动代码(Driver)指调用被测函数的代码。在单元测试中,驱动模块通常包括调用被测函数前的数据准备、调用被测函数以及验证相关结果 三个步骤。通常驱动代码的结构,由单元测试的框架决定。
桩代码(Stub)是用来代替真实代码的临时代码。如:某个函数A的内部实现中调用来一个尚未实现的函数B,为了对函数A的逻辑进行测试,那么需要模拟一个函数B,这个模拟的函数B的实现就是所谓的桩代码

举例:


13191251-2b81b11fb829493f.png
函数A是被测函数

可见,函数A中调用来函数B,但在单元测试阶段函数B尚未实现,用一个假的函数B来代替真实的函数B,这个假的函数B就是桩函数。

13191251-fcb2cd44cb724511.png
桩函数(函数B)的实现

可见 桩代码的应用首先起到了隔离和补齐的作用,使被测代码能够独立编译、链接、并独立运行。同事,桩代码还具有被测函数执行路径的作用。
编写桩代码需遵守三大原则:

  • 桩函数要具有原函数完全相同的原形,仅仅是内部实现不同,这样测试代码才能连接到桩函数;
  • 用于实现隔离和不起的桩函数比较简单,只需要保持原函数的声明,加一个空的实现,目的是通过编译连接;
  • 实现控制功能的桩函数是应用最广泛的,要根据测试用例的需要,输出合适的数据作为被测函数的内部输入。

Mock和桩代码非常类似,用来代替真实代码的临时代码,起到隔离和补齐的作用。


13191251-7db0874c635afd19.png
Mock和Stub的区别

实际项目中如何开展单元测试?

1、通常只有底层模块或核心模块的测试才会采用单元测试;
2、需要确定单元测试框架,与开发语言相关。如,Java-Junit&TestNG;C/C++-CppTest$Parasoft C/C++test;桩代码和Mock代码框架选型是一句开发所采用的具体技术栈。
3、代码覆盖率统计工具,Java的JaCoCo;JavaScript的Istanbul。
4、需要吧单元测试执行,代码覆盖率统计和持续集成流水线做集成,以确保每次代码递交,会自动触发单元测试。以单元测试通过率和代码覆盖率作为本次提交代码能够被接受。

文章引用:
https://time.geekbang.org/column/article/10275

猜你喜欢

转载自blog.csdn.net/weixin_34200628/article/details/90819662