软件测试之单元测试详解

news/2024/11/15 6:42:05/

目录

前言:

1、什么是单元测试?

2、什么是好的单元测试?

3、怎么写单元测试?

4、玩转单元测试


前言:

单元测试是软件测试中的一种测试方法,用于验证代码中最小可测试单元的正确性。它主要关注对程序的各个独立模块、函数或方法进行测试,以确保其按照预期产生正确的输出结果。

单元测试的目的是隔离和测试程序的各个组成部分,以验证其功能的正确性和稳定性。通过在开发过程中频繁运行单元测试,开发人员可以及早发现和修复潜在的问题,减少后期集成和系统测试阶段的错误。

1、什么是单元测试?

在正式阐述什么是单元测试之前,我先给大家分享一个工厂组装手机的例子。

手机组装流水线按照图纸将各个电子元件组装焊接为各个模块组件(如喇叭,听筒,麦克,FPC,按键板,摄像头,LCD等),再将各个模块组件组装成一部完整的手机。

如果一起顺利,在给手机安装系统后就可以正常使用了。但是很不幸,大多数情况下的手机是无法使用的,那么就需要将已经组装好的手机重新拆机,逐个模块排查问题,在每个模块排查中需要对每个电子元件进行检测,通过花费大量的时间和精力才能定位到问题原因。

那么在后续的生产中,如何才能避免这种问题的发生呢?

你可能立即就会想到,为什么不在组装焊接前,就先测试每个要用到的电子元器件呢?这样你就可以先排除有问题的元器件,最大程度地防止组装完成后逐级排查问题的事情发生。

实践也证明,这的确是一个行之有效的好办法。

如果把手机的生产、测试和软件的开发、测试进行类比,你可以发现:

电子元器件就像是软件中的单元,通常是函数或者类,对单个元器件的测试就像是软件测试中的单元测试

组装完成的功能模块组件如喇叭,听筒,麦克,FPC,按键板,摄像头,LCD等就像是软件中的模块,对功能模块组件的测试就像是软件中的集成测试

手机全部组装并安装系统就像是软件完成了预发布版本,手机全部组装并安装系统完成后的开机测试就像是软件中的系统测试

单元测试是指,对软件中的最小可测试单元在与程序其他部分相隔离的情况下进行检查和验证的工作,这里的最小可测试单元通常是指函数或者类。

2、什么是好的单元测试?

好的单元测试应当包含四种特性:正确清晰完整健壮

  • 正确:单元测试是最基础的要求,必须要保证所写的函数或者类实现的功能是正确的,如果实现的功能都不能满足,那就是缺陷!

  • 清晰:单元测试可以帮助其他开发理解函数或者类的实现,所以要求单元测试用例简洁、清晰,需要有良好的可读性

  • 完整:单元测试需要考虑输入与输出组合的各种场景,保证单元测试的覆盖率

  • 健壮:健壮性是最容易被忽略的一项,当被测试的类或者函数被修改内部实现或者添加功能时,⼀个好的单测应该完全不需要被修改或者只有极少的修改。⽐如⼀个排序函数的单测实现是完全稳定的,它不应该跟着不同的排序算法⽽变化

3、怎么写单元测试?

可能大多数的测试人员不会接触到单元测试的编写,因为按照我个人的看法,开发人员根据自己写的代码编写单测用例是最合适不过的,也是最高效的

虽然我们不需要实际去编写单测用例,但是我们还是需要了解怎么写单元测试。

单元测试的代码结构一般包含三部分:分别是准备调用断言

  • 准备:准备部分的⽬的是准备好调⽤所需要的外部环境,如数据,Stub(桩代码),Mock,临时变量,调⽤请求,环境背景变量等等。

  • 调用:调⽤部分则是实际调⽤需要测试⽅法,即函数或者流程本身。

  • 断言:断⾔部分判断调⽤部分的返回结果是否符合预期。

每个单元测试都应该能清晰地分出这三部分,当然有时调⽤断⾔两部分合在⼀起也是⽐较常见的。

4、玩转单元测试

下面我们来聊聊单元测试编写用例的相关知识,首先我们需要了解单元测试的三个重要部分,即驱动程序桩程序Mock

驱动程序:驱动程序(Driver)也称作驱动模块,用以模拟被测模块的上级模块,能够调用被测模块。在测试过程中,驱动模块接收测试数据,调用被测模块并把相关的数据传送给被测模块。

简单说就是你负责测试的模块没有main()方法入口,所以需要写一个带main的方法来调用你的模块或方法。这个就是驱动测试

桩程序:桩程序(Stub),也称桩模块,用以模拟被测模块工作过程中所调用的下层模块,即被测模块本身调用的其他关联函数。桩模块由被测模块调用,它们一般只进行很少的数据处理。

桩是指用来代替关联代码或者未实现的代码,为了让测试对象可以正常的执行,其实一般会硬编码一些输入和输出,保证被测模块能够正常运行

Mock:Mock除了保证Stub的功能之外,还可深入的模拟对象之间的交互方式,如:调用了几次、在某种情况下是否会抛出异常以及提供数据断言

接下来我们通过一个实例来学习单元测试用例的编写

 
# 待测试的方法
def calculator(type):# 调用桩代码获取数据num1 = __stub1()num2 = __stub2()# 调用mockmock_data = __mock_check()# +if type.lower() == 'add':type = 'add'ret = num1+num2assert ret == mock_data[type]print('{} + {} = {}'.format(num1,num2,ret))return ret# -if type.lower() == 'minus':type = 'minus'ret = num1-num2assert ret == mock_data[type]print('{} - {} = {}'.format(num1,num2,ret))return ret# *if type.lower() == 'multiply':type = 'multiply'ret = num1*num2assert ret == mock_data[type]print('{} * {} = {}'.format(num1,num2,ret))return ret# /if type.lower() == 'divide':type = 'divide'if num2 == 0:print('除法分母不能为0')return '除法分母不能为0'else:ret = num1/num2assert ret == mock_data[type]print('{} / {} = {}'.format(num1,num2,ret))return ret# 桩代码1
def __stub1():output = 20print('my stub的值是{}'.format(output))return output# 桩代码2
def __stub2():output = 5print('my stub的值是{}'.format(output))return output# Mock代码 => 提供断言数据
def __mock_check():mock_result = {}mock_result['add'] = 25mock_result['minus'] = 15mock_result['multiply'] = 100mock_result['divide'] = 4return mock_result# 驱动程序
if __name__=="__main__":print(calculator('add'))print(calculator('minus'))print(calculator('multiply'))print(calculator('divide'))

上面提供的是一个简单的单元测试,包含了驱动程序、被测对象、桩程序以及Mock代码

驱动程序main作为被测对象的上级模块,运行时调用被测函数calculator

被测函数calculator被调用后,通过桩代码__stub1__stub2提供测试数据

被测函数calculator通过不同的入参匹配不同的场景,不同场景获取的结果与Mock函数__mock_check进行比对断言,校验结果是否符合预期

被测函数成功返回如下:

my stub的值是20
my stub的值是5
20 + 5 = 25
25

被测函数失败返回如下:

my stub的值是20
Traceback (most recent call last):
my stub的值是5File "/Users/luozelin/Desktop/demo/unittest_demo/ut_demo.py", line 73, in <module>print(calculator('add'))File "/Users/luozelin/Desktop/demo/unittest_demo/ut_demo.py", line 21, in calculatorassert ret == mock_data[type]
AssertionError

 作为一位过来人也是希望大家少走一些弯路,在这里我给大家分享一些自动化测试前进之路的必须品,希望能对你带来帮助。(WEB自动化测试、app自动化测试、接口自动化测试、持续集成、自动化测试开发、大厂面试真题、简历模板等等),相信能使你更好的进步!

留【自动化测试】即可【自动化测试交流】:574737577(备注ccc)icon-default.png?t=N5K3http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=2YZ9KmgKz7Ct4hytfx98cflRXezd07-I&authKey=UYKMsSwnKqdYn6xCgrgs3wSIpRW5ufHVkTStLlc7XeJlSgfYGJPF%2FzVXEjwwn%2Fdm&noverify=0&group_code=574737577

 

 

 


http://www.ppmy.cn/news/746435.html

相关文章

web前端设计师的具体职责

web前端设计师的具体职责 web前端设计师负责将设计图转化成页面&#xff0c;并实现页面动态效果&#xff0c;并配合后端程序员嵌入数据。下面是学习啦小编整理的web前端设计师的具体职责。 web前端设计师的具体职责1 职责&#xff1a; 1.负责网站页面的整体美工创意、设计与…

C1010 unexpected end file of file while looking for precompiled header.

往c项目中添加文件时遇到了这个错误 C1010 unexpected end file of file while looking for precompiled header. Did you forget to add #include "XXXXX.h" to your source? 项目属性设置了预编译头文件&#xff0c;报错位置为cpp文件 发现问题出现在cpp文件的…

如何解决 fatal error C1010

使用visual C6.0运行时&#xff0c;出现fatal error C1010:unexpected end of … 出现这种错误的原因&#xff0c;是因为没有添加"#include<stdafx.h>"这个头文件。 解决方法就是在代码的第一行加一条语句&#xff1a;#include<stdafx.h>.

如何解决:fatal error C1010: unexpected end of file while looking for precompile

在编译VC6.0是,出现fatal error C1010: unexpected end of file while looking for precompiled header directive 的错误.解决方法&#xff1a; 1、如果发生错误的文件是由其他的C代码文件添加进入当前工程而引起的&#xff0c;则AltF7进入当前工程的 Settings&#xff0c;选…

解决VS2013编译错误error C1010: unexpected end of file while looking for precompiled header

解决VS2013编译错误error C1010: unexpected end of file while looking for precompiled header 本人遇到这个错误是在调用了别的串口类时出现的 Error 2 error C1010: unexpected end of file while looking for precompiled header. Did you forget to add #include "…

VS C1001错误可能的解决方案

问题描述&#xff1a; … fatal error C1001: 编译器中发生内部错误。 3> (编译器文件“f:\dd\vctools\compiler\utc\src\p2\main.c”&#xff0c;第 xxx 行) 3> 要解决此问题&#xff0c;请尝试简化或更改上面所列位置附近的程序。 3> 请选择 Visual C 3> “…

c010101

求一个数中 二进制表示的时候 1的个数 int i ; int cout 0; while (i) { cout; ii&(i-1); } 判断一个数二进制中多少个0 同上 判断一个数是否是2个n次方 int integr ; if((integer&(integer-1)) 0) printf(“ok”); integer – 1 将二进制数据最后一位变成…

vc6.o--fatal error C1010错误的解决

当编译c文件时,出错信息为:fatal error C1010: unexpected end of file while looking for precompiled header directive ================================================================================= 解决方案: 1、如果发生错误的文件是由其他的C代码文件添加进…