1)掌握单元测试的方法
2) 学习XUnit测试原理及框架;
3)掌握使用测试框架进行单元测试的方法和过程。
单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。总的来说,单元就是人为规定的最小的被测功能模块。单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。单元测试是由程序员自己来完成,最终受益的也是程序员自己。可以这么说,程序员有责任编写功能代码,同时也就有责任为自己的代码编写单元测试。执行单元测试,就是为了证明这段代码的行为和我们期望的一致。
单元测试的内容包括模块接口测试、局部数据结构测试、路径测试、错误处理测试、边界测试
(1)模块接口测试
模块接口测试是单元测试的基础。只有在数据能正确流入、流出模块的前提下,其他测试才有意义。模块接口测试也是集成测试的重点,这里进行的测试主要是为后面打好基础。
(2)局部数据结构测试
检查局部数据结构是为了保证临时存储在模块内的数据在程序执行过程中完整、正确,局部功能是整个功能运行的基础。重点是一些函数是否正确执行,内部是否运行正确。局部数据结构往往是错误的根源,应仔细设计测试用例,力求发现下面几类错误
(3)边界条件测试
边界条件测试是单元测试中最重要的一项任务。众所周知,软件经常在边界上失效,采用边界值分析技术,针对边界值及其左、右设计测试用例,很有可能发现新的错误。边界条件测试是一项基础测试,也是后面系统测试中的功能测试的重点,边界测试执行的较好,可以大大提高程序健壮性。
(4)独立路径测试
在模块中应对每一条独立执行路径进行测试,单元测试的基本任务是保证模块中每条语句至少执行一次。测试目的主要是为了发现因错误计算、不正确的比较和不适当的控制流造成的错误。具体做法就是程序员逐条调试语句。
(5)错误处理测试
检查模块的错误处理功能是否包含有错误或缺陷。例如,是否拒绝不合理的输入;出错的描述是否难以理解、是否对错误定位有误、是否出错原因报告有误、是否对错误条件的处理不正确;在对错误处理之前错误条件是否已经引起系统的干预等。
通常单元测试在编码阶段进行。在源程序代码编制完成,经过评审和验证,确认没有语法错误之后,就开始进行单元测试的测试用例设计。利用设计文档,设计可以验证程序功能、找出程序错误的多个测试用例。对于每一组输入,应有预期的正确结果。
xUnit是各种代码驱动测试框架的统称,这些框架可以测试 软件的不同内容(单元),比如函数和类。xUnit框架的主要优点是,它提供了一个自动化测试的解决方案。可以避免多次编写重复的测试代码。
Unit测试框架包括四个要素:
(1)测试目标(对象)
一组认定被测对象或被测程序单元测试成功的预定条件或预期结果的设定。Fixture就是被测试的目标,可以是一个函数、一组对象或一个对象。 测试人员在测试前应了解被测试的对象的功能或行为。
(2)测试集
测试集是一组测试用例,这些测试用例要求有相同的测试Fixture,以保证这些测试不会出现管理上的混乱。
(3)测试执行
单个单元测试的执行可以按下面的方式进行:
第一步 编写 setUp() 函数,目的是:建立针对被测试单元的独立测试环境;举个例子,这可能包含创建临时或代理的数据库、目录,再或者启动一个服务器进程。
第二步 编写所有测试用例的测试体或者测试程序;
第三步 编写tearDown()函数,目的是:无论测试成功还是失败,都将环境进行清理,以免影响后续的测试;
(4)断言
断言实际上就是验证被测程序在测试中的行为或状态的一个函数或者宏。断言的失败会引发异常,终止测试的执行。
1.3 面向特定语言的
基于xUnit框架的自动化测试框架
CPPunit:主要测试用C++语言编写的代码
一、源码
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <time.h> 4 5 int plus(int x, int y) 6 { 7 if (x+y<= 100) 8 return x+y; 9 else 10 return -1; 11 } 12 13 int subtract(int x, int y) 14 { 15 if (x-y > 0) 16 return x-y; 17 else 18 return -1; 19 } 20 21 int multiply(int x, int y) 22 { 23 if (x*y < 100) 24 return x*y; 25 else 26 return -1; 27 } 28 29 int divide(int x, int y) 30 { 31 if (x > y && y != 0 && (double)x / y - x / y == 0) //被除数必须大于除数 32 return x/y; 33 else 34 return -1; 35 } 36 37 void main() 38 { 39 int x,y,t; //定义两个操作数x,y,结果z,输入结果t 40 char k; //运算符k可取“+、-、×、÷” 41 int i,sum=0; //题目数量i,答对数目sum 42 srand(time(0)); 43 44 printf("小学100以内四则运算练习题!!\n"); 45 for(i=0;i<10;i++) 46 { 47 x=rand()%100+1; 48 y=rand()%100+1; 49 k=rand()%4; //0表加,1表减,2表乘,3表除 50 51 /**< 数据合格判断及算式显示 */ 52 printf("第%d题:",i+1); 53 switch(k) 54 { 55 case 0: 56 if(plus(x,y)>0) //保证和在100内 57 { 58 printf("%d + %d = ",x,y); 59 scanf("%d",&t); 60 if(t==plus(x,y)) 61 { 62 sum++; 63 printf("正确\n"); 64 } 65 else 66 printf("错误\n"); 67 } 68 else 69 i--; 70 break; 71 case 1: 72 if(subtract(x,y)>=0) //差大于0 73 { 74 printf("%d - %d = ",x,y); 75 scanf("%d",&t); 76 if(t==subtract(x,y)) 77 { 78 sum++; 79 printf("正确\n"); 80 } 81 else 82 printf("错误\n"); 83 } 84 else 85 i--; 86 break; 87 case 2: 88 if(multiply(x,y)>=0) //保证积小于100 89 { 90 printf("%d × %d = ",x,y); 91 scanf("%d",&t); 92 if(t==multiply(x,y)) 93 { 94 sum++; 95 printf("正确\n"); 96 } 97 else 98 printf("错误\n"); 99 } 100 else 101 i--; 102 break; 103 case 3: 104 if(divide(x,y)>0) //被除数必须大于除数 105 { 106 printf("%d ÷ %d = ",x,y); 107 scanf("%d",&t); 108 if(t==divide(x,y)) 109 { 110 sum++; 111 printf("正确\n"); 112 } 113 else 114 printf("错误\n"); 115 } 116 else 117 i--; 118 break; 119 } 120 121 } 122 /**< 输出答对题数和得分 */ 123 printf("答对 %d 题,得分:%d\n",sum,sum*10); 124 if(sum<=6) 125 printf("错误较多,请继续努力!\n"); 126 else if(sum<=9) 127 printf("加油,你会做得更好!\n"); 128 else 129 printf("你真棒!!!") ; 130 }
二、测试用例设计
测试用例、输入数据及预期输出。输入数据是测试用例的核心,对输入数据的定义是:被测试函数所读取的外部数据及这些数据的初始值。外部数据是对于被测试函数来说的,实际上就是除了局部变量以外的其他数据,老纳把这些数据分为几类:参数、成员变量、全局变量、IO媒体。IO媒体是指文件、数据库或其他储存或传输数据的媒体,例如,被测试函数要从文件或数据库读取数据,那么,文件或数据库中的原始数据也属于输入数据。一个函数无论多复杂,都无非是对这几类数据的读取、计算和写入。预期输出是指:返回值及被测试函数所写入的外部数据的结果值。返回值就不用说了,被测试函数进行了写操作的参数(输出参数)、成员变量、全局变量、IO媒体,它们的预期的结果值都是预期输出。一个测试用例,就是设定输入数据,运行被测试函数,然后判断实际输出是否符合预期。
进行减法用例的设计:
当函数进行正常运行时使用正常流程进行输出运算并返回两数的和
当函数不能进行正常的运算时应进行错误返回-1以进行后面的数值的再次生成
边界值问题应保证数值在100以内,以及两个数的本身的值也应该在100以内正整数进行if语句进行判断是否符合规则
应保证每一个基本用例至少执行一次以确保程序的运行
其他算法原理类似
三、选择的测试框架介绍、安装过程
选用MiniUnit未找到相关资料难以进行有效测试,经多次查找在博客园找到别的学校的博客实验记录参考使用VS2019进行C语言的单元测试
参考链接https://www.cnblogs.com/dzqeeee/p/10700798.html,https://www.cnblogs.com/czhao4/p/10021011.html
单独的单元测试工程一般是为了测试暴露给外部程序调用的接口,这样可以保证调用者(单元测试程序)和被调用者(接口)的分离。不过有些时候,我们也要给工程的内部关键方法写一些单元测试,这个时候就需要将测试用例写在工程内部。
(1)进行VS2019安装,安装后可以进行软件内的单元测试不需要借助别的插件
(2)打开VS2019进行工程的创建,并输入工程名称
(3)在工程处进行文件的加入包含头文件和源文件,按照自己代码的实际情况进行选择性输入即可
(4)进行工程的运行以产生.obj文件以供引用后进行右键点击解决方案进行添加新建项目并选择本机单元测试并输入名称
(5) 右键测试项目后选择属性进行.obj的引入,右键引用进行加入
(6)接着进行单元测试代码的编写,发现错误提醒及时修改即可(在头文件中包含源代码的头文件)
四、测试代码
#include "pch.h"
#include "CppUnitTest.h"
#include "..\单元测试\test.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace UnitTest1
{
TEST_CLASS(UnitTest1)
{
public:
TEST_METHOD(Plus)
{
Assert::AreEqual(plus(12, 28), 40);
Assert::AreEqual(plus(63, 23), 86);
Assert::AreEqual(plus(63, 83), -1);
}
TEST_METHOD(Subtract)
{
Assert::AreEqual(subtract(45, 12), 33);
Assert::AreEqual(subtract(65, 9), 56);
Assert::AreEqual(subtract(65, 79), -1);
}
TEST_METHOD(Multiply)
{
Assert::AreEqual(multiply(5, 17), 85);
Assert::AreEqual(multiply(3, 9), 27);
Assert::AreEqual(multiply(13, 9), -1);
}
TEST_METHOD(Divide)
{
Assert::AreEqual(divide(99, 11), 9);
Assert::AreEqual(divide(50, 2), 25);
Assert::AreEqual(divide(70, 8), -1);
}
};
}
五、测试结果与分析
进行断言的构造后进行运行全部测试并进行测试资源管理器显示即可查看是否通过单元测试,经查看四种运算的函数都通过了单元测试
进行GitHub的资料上传
比较以下二个工匠的做法,你认为哪种好?结合编码和单元测试,谈谈你的认识。
二者各有不同,工匠一的做法好在进行基础叠加时按照固定标准进行可以使后续更加有条理,在进行中便于发现异常情况,在进行检查测试时只需要按照一条标准修改不需要再次寻找标点。
工匠二的方法适应于小的项目进行快速的添加后在进行修正
实验小结
1、进行单元测试时应该多方面考虑,由于自身原因未能进行MiniUnit的使用到单元测试中去(主要是没找到资料难以参考不会使用)
2、大部分的资料关于C++,Java,Python,关于C语言单元测试相对过少
3、进行测试时应考虑边界问题即数值的范围和产生数的范围
4、单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。总的来说,单元就是人为规定的最小的被测功能模块。单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。
原文:https://www.cnblogs.com/scy2020/p/12921843.html