当前位置: 首页 > news >正文

单元测试知识总结

我们希望每段代码都是自测试的,每次改动之后,都能自动发现对现有功能的影响。

1 测试要求

在对软件单元进行动态测试之前,应对软件单元的源代码进行静态测试;

应建立测试软件单元的环境,如数据准备、桩模块、模拟器。

对软件设计文档规定的软件单元的功能、性能、接口等应逐项进行测试。

每个软件特性应至少被一个正常测试用例和一个被认可的异常测试用例覆盖

测试用例的输入应至少包括 有效等价类值、无效等价类值 和 边界数据值;

语句覆盖率要达到要求(如70%);

分支覆盖率要达到要求(如70%);

对输出数据正确与否 及 其格式进行测试。

2 单元测试任务

模块接口测试;

模块局部数据结构测试;

模块边界条件测试;

模块中独立执行路径测试;

模块的错误处理路径测试。

3 静态分析

控制流分析:根据设计文档定义的控制流程,分析被测试程序是否按要求运行。

数据流分析:用控制流程图来分析数据发生的异常情况,这些异常包括被初始化、被赋值或被引用过程中行为序列的异常。数据流分析也作为数据流测试的预处理过程

推荐使用“TDD测试驱动开发”的方式,开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么代码产品,之后再开始真正的业务需求开发。

4 动态测试

4.1 功能测试

功能测试是对软件设计中的软件单元逐项进行的测试,以验证其功能是否满足要求。

功能测试一般需进行:

用正常值的等价类输入数据值测试;

用非正常值的等价类输入数据值测试;

进行每个功能的合法边界值和非法边界值输入的测试;

用一系列真实的数据类型和数据值运行,测试超负荷、饱和及其他“最坏情况”的结果

4.2 接口测试

接口测试是对软件设计文档中的外部/内部接口逐项进行的测试。

接口测试一般需进行:

测试所有外部/内部接口,检查接口信息的格式和内容;
对每一个外部/内部输入/输出接口必须进行正常和异常情况的测试

4.3 边界测试

边界测试是对软件处在边界或端点情况下运行状态的测试。

边界测试一般需进行:

软件的输入域或输出域的边界或端点的测试;
状态转换的边界或端点的测试;
功能界限的边界或端点的测试;
性能界限的边界或端点的测试;
容量界限的边界或端点的测试。

4.4 逻辑测试

逻辑测试是测试程序逻辑结构的合理性、实现的正确性。逻辑测试应由测试人员利用程序内部的逻辑结构及有关信息,设计或选择测试用例,对程序所有逻辑路径进行测试。通过在不同点检查程序的状态,确定实际的状态是否与预期的状态一致。

逻辑测试应满足覆盖率的要求,一般需进行:

  • 语句覆盖;
  • 分支覆盖;
  • 条件覆盖;
  • 条件组合覆盖;
  • 路径覆盖。

5 单元测试用例设计方法

等价类划分、边界值分析、逻辑覆盖法、基本路径测试法

5.1 等价类划分

等价类划分的方法是把程序的输入划分成若干等价类部分,然后从每个部分中选取少数代表性数据当作测试用例。

确定等价类原则:

  • 如果输入变量定义了一个取值范围(例如正常取值为[1,999]),那么就应确定一个有效等价类(1≤输入≤999),以及两个无效等价类(输入<1,输入>999);
  • 如果输入变量为枚举类型,或对于规定的有限输入值集合分别进行不同的处理,那么应对每一个输入确定一个有效等价类,并确定一个无效等价类;
  • 如果对输入变量进行逻辑判断,那么应对逻辑条件满足与否分别确定一个有效等价类和一个无效等价类;
  • 如果输入变量作为数组下标或指针使用,那么应根据规定的数组元素个数,分别确定有效等价类和无效等价类。

5.2 边界值分析

  • 如果规定了变量的输入范围,那么应该对范围的边界设计测试用例;对于未具体规定取值范围的输入变量,应考虑对变量数据类型所能达到的最大范围的上下限设计测试用例;
  • 如果规定了数组、循环逻辑次数等数量,应针对最小、最大数量值的边界设计测试用例;
  • 如果规定了输出变量的范围,还应考虑针对输出变量范围边界所对应的输入变量数值设计测试用例;
    在这里插入图片描述
  • 对各边界条件的上点和离点作为测试输入数据
  • 如果输入条件规定了值的个数,则用最大个数,最小个数,比最小个数少一,比最大个数多一的数作为测试数据
  • 如果程序的规格说明给出的输入域或输出域是有序集合,则应选取集合的第一个元素和最后一个元素作为测试用例

5.3 逻辑覆盖法

逻辑覆盖法是根据程序内部逻辑覆盖满足性设计测试用例的白盒测试方法。

(1)语句覆盖:就是设计若干个测试用例,运行被测程序,使得每一可执行语句至少执行一次。

(2)分支覆盖:(判定覆盖)使设计的测试用例保证程序中每个判断的每个取值分支至少经历一次。但若程序中的判定是有几个条件联合构成时,它未必能发现每个条件的错误;

(3)条件覆盖:条件覆盖是指选择足够的测试用例,使得运行这些测试用例时,判定中每个条件的所有可能结果至少出现一次,但未必能覆盖全部分支;

(4)分支 / 条件覆盖:分支/条件覆盖是使判定中每个条件的所有可能结果至少出现一次,并且每个分支本身的所有可能结果也至少出现一次;
(5)条件组合覆盖:条件组合覆盖是使每个分支中条件结果的所有可能组合至少出现一次,因此分支本身的所有可能结果也至少出现一次

(6)路径覆盖:是每条可能执行到的路径至少执行一次。

补充:
(1)语句覆盖在所有的测试方法中是一种最弱的覆盖。
(2)判定覆盖和条件覆盖比语句覆盖强,满足判定/条件覆盖标准的测试用例一定也满足判定覆盖、条件覆盖和语句覆盖
(3)路径覆盖也是一种比较强的覆盖,但未必考虑判定条件结果的组合,并不能代替条件覆盖和条件组合覆盖。

举个例子吧:

if A and B then Action1
if C or D then Action2语句覆盖最弱,只需要让程序中的语句都执行一遍即可 。上例中只需设计测试用例使得A=true B=true C=true 即可。分支覆盖又称判定覆盖:使得程序中每个判断的取真分支和取假分支至少经历一次,即判断的真假均曾被满足。上例需要设计测试用例使其分别满足下列条件即可(1)A=true,B=true,C=true,D=false(2)A=true,B=false,C=false,D=false。条件覆盖:要使得每个判断中的每个条件的可能取值至少满足一次。上例中第一个判断应考虑到A=true,A=false,B=true,B=false第二个判断应考虑到C=true,C=false,D=true,D=false,所以上例中可以设计测试用例满足下列条件(1)A=true,B=true,C=true,D=true(2)A=false,B=false,C=false,D=false。路径覆盖:要求覆盖程序中所有可能的路径。所以可以设计测试用例满足下列条件(1)A=true,B=true,C=true,D=true(2)A=false,B=false,C=false,D=false(3)A=true,B=true,C=false,D=false(4)A=false,B=false,C=true,D=true。不论那种覆盖方法,都不能保证程序的正确性。
一般测试书中讲白盒测试的逻辑覆盖部分时都会对这几种覆盖作比较,而且都给出了例子。

我们要求的是分支覆盖。

5.4 基本路径测试

在这里插入图片描述
上图中,独立路径有5条,即需要有5个测试用例覆盖。

我们会统计独立路径的覆盖率。

代码规范中对方法复杂度有要求,一个方法的复杂度太高,容易出错且难以测试。

6 单元测试的实现方法

6.1 mock

单元测试不是集成测试,只测试自身的逻辑;因此,我们使用mockito库,模拟返回外部接口或者其它函数的结果

6.3 数据准备

使用@Sql

7 单元测试与集成测试

写单元测试时,容易有一个误区,就是都写的集成测试,而没有对某个方法写单元测试,这其实是一种想要偷懒但其实低效的方法,包括编写、运行、效果都是低效的。

对每个层进行特定的测试方法,会更新高效。

单元测试与集成测试的比例大概是3:1。使用单元测试去覆盖分支,效率会更高。

使用gradle 的JVM Test Suite Plugin划分单元测试与集成测试集,分开执行,单元测试开启gradle的并行运行模式。

7.1 controller层

这层主要,测试参数校验。

需要使用“@WebMvcTest”注解。

mock掉service

@WebMvcTest(EmployeeController.class)
public class StandaloneControllerTests {@MockBeanEmployeeService employeeService;@AutowiredMockMvc mockMvc;@Testpublic void testfindAll() throws Exception {Employee employee = new Employee("Lokesh", "Gupta");List<Employee> employees = Arrays.asList(employee);Mockito.when(employeeService.findAll()).thenReturn(employees);mockMvc.perform(get("/employee")).andExpect(status().isOk()).andExpect(jsonPath("$", Matchers.hasSize(1))).andExpect(jsonPath("$[0].firstName", Matchers.is("Lokesh")));}}

7.2 service层

主要的业务逻辑层,需要对各个业务分支代码进行测试,是单元测试最多的层。

使用mock,不需要使用“@SpringBootTest”注解,运行和编写的效率更高。

@ExtendWith(MockitoExtension.class)
public class ServiceTests {@InjectMocksEmployeeService service;@MockEmployeeRepository dao;@BeforeEachpublic void init() {MockitoAnnotations.openMocks(this);}@Testvoid testFindAllEmployees() {List<Employee> list = new ArrayList<Employee>();Employee empOne = new Employee("John", "John");Employee empTwo = new Employee("Alex", "kolenchiski");Employee empThree = new Employee("Steve", "Waugh");list.add(empOne);list.add(empTwo);list.add(empThree);when(dao.findAll()).thenReturn(list);//testList<Employee> empList = service.findAll();assertEquals(3, empList.size());verify(dao, times(1)).findAll();}@Testvoid testCreateOrSaveEmployee() {Employee employee = new Employee("Lokesh", "Gupta");service.save(employee);verify(dao, times(1)).save(employee);}
}

7.3 dao层

需要准备数据到数据库,测试复杂sql编写是否正确。

这个层的测试分支覆盖情况工具会统计的不全面,特别是使用mysql的时候,需要开发自觉测试各种情况。

注解@AutoConfigureTestDatabases可以配置使用内存数据库

@DataJpaTest 会禁用auto-configuration,只配置JPA测试需要用到的配置。

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class DaoTests {@AutowiredEmployeeRepository employeeRepository;@Testpublic void testCreateReadDelete() {Employee employee = new Employee("Lokesh", "Gupta");employeeRepository.save(employee);Iterable<Employee> employees = employeeRepository.findAll();Assertions.assertThat(employees).extracting(Employee::getFirstName).containsOnly("Lokesh");employeeRepository.deleteAll();Assertions.assertThat(employeeRepository.findAll()).isEmpty();}
}

7.4 其它工具类

使用utils类

大部分都是单元测试,尽量不要添加“@SpringBootTest”注解

7.5 集成测试

测试整个路径,包括从controller接收请求并返回,到数据库修改。

使用@SpringBootTest

相关文章:

单元测试知识总结

我们希望每段代码都是自测试的&#xff0c;每次改动之后&#xff0c;都能自动发现对现有功能的影响。 1 测试要求 在对软件单元进行动态测试之前&#xff0c;应对软件单元的源代码进行静态测试&#xff1b; 应建立测试软件单元的环境&#xff0c;如数据准备、桩模块、模拟器…...

Android:使用Service处理息屏后的WebSocket的服务端推送消息并传递给前端

前言 之前我们在使 RESTful 访问服务端时&#xff0c;一般都是客户端请求服务端应答的方式&#xff0c;这种通讯方式&#xff0c;对于需要持续获取数据的情形都是采用轮询的方式&#xff0c;但是这种方式对两边的性能消耗很大&#xff0c;特别是服务端的压力很大。现在当我们使…...

Git Bash Here 中文显示乱码的处理方法

在使用"open Git Bash Here"时&#xff0c;遇到中文显示乱码问题。 原因&#xff1a;通常是由于编码设置不正确导致的。 open Git Bash Here —>鼠标右击空白处&#xff0c;点击「选项」|或「Options」 在「文本」或 「Text」选项卡中&#xff0c;找到"local…...

FreeBSD安装教程

FreeBSD 是一个功能强大且可靠的开源 UNIX 操作系统&#xff0c;适合服务器和桌面环境。本文将介绍如何安装 FreeBSD&#xff0c;从系统准备到基础设置&#xff0c;为你快速上手提供帮助。 一、准备工作 1. 硬件要求 CPU&#xff1a;支持 x86 或 AMD64 架构的处理器。 内存&a…...

Loki 各模式简介

目录 Loki 部署模式 单片模式 简单可扩展 微服务模式 Loki 部署模式 Loki 是一个由许多微服务组成的分布式系统。它还具有独特的构建模型&#xff0c;其中所有这些微服务都存在于同一个二进制文件中。 您可以使用命令行标志配置单个二进制文件的行为-target&#xff0c;以指…...

MySQL八股-全局锁,表级锁,表锁,元数据锁,意向锁,行级锁,行锁,间隙锁,临键

文章目录 全局锁表级锁表锁(表级锁)元数据锁(MDL&#xff0c;Meta Data Lock&#xff0c;表级锁)元数据锁演示元数据锁兼容的情况元数据锁互相阻塞的情况 意向锁&#xff08;Intention lock&#xff0c;表级锁&#xff09;意向锁分类意向锁演示&#xff1a;意向共享锁(**IS**)与…...

(四)Spring Cloud Alibaba 2023.x:高效构建 Gateway 网关服务

目录 前言 准备 项目集成 pom.xml引入依赖 启动类 yml文件添加网关配置 修改消费者FeignService类 结果验证 前言 Spring cloud alibaba 体系中构建微服务&#xff0c;我们使用Spring Cloud Gateway 作为服务网关&#xff0c; Gateway是Spring 官方推出的一款基于 Web…...

Android XR 是什么?解释它的功能、设备、开发工具等

什么是“Android XR”&#xff1f; Android XR是最新配备AI的OS&#xff08;操作系统&#xff09;&#xff0c;兼容耳机和眼镜&#xff08;AR眼镜&#xff09;。 沉浸式剧场 从视频列表中选择... 您可以体验完全身临其境的视频观看体验。 无限工作空间 您的现实世界将成为您…...

【算法】实体关系抽取

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…...

Codeforces Round 993 (Div. 4)题解

A. Easy Problem 思路&#xff1a;经过看了一眼&#xff0c;我们发现&#xff0c;ab的和一定是n&#xff0c;且两个都是正整数&#xff0c; 所以a的范围就是从1~n-1 所以输出n-1即可 #include<bits/stdc.h> using namespace std; #define int long long int t; int n…...

【计算机网络】期末考试预习复习|中

作业讲解 转发器、网桥、路由器和网关(4-6) 作为中间设备&#xff0c;转发器、网桥、路由器和网关有何区别&#xff1f; (1) 物理层使用的中间设备叫做转发器(repeater)。 (2) 数据链路层使用的中间设备叫做网桥或桥接器(bridge)。 (3) 网络层使用的中间设备叫做路…...

从零用java实现 小红书 springboot vue uniapp (4)个人主页优化

前言 移动端演示 http://8.146.211.120:8081/#/ 前面的文章我们基本完成了详情页开发 今天我们具体的去进行实现个人中心 并且分享我开发时遇到的问题 首先先看效果 我们对布局整体规划一下 个人名片 半透明背景 刚开始我用的是 <view style"background-image: ur…...

为“行车大脑”降温:Simdroid-EC助力汽车ECU设计研发

ECU&#xff08;Electronic Control Unit&#xff0c;电子控制单元&#xff09;被誉为汽车的行车大脑&#xff0c;在工作时会产生大量的热量&#xff0c;而其散热存在以下难题&#xff1a;一是工作环境恶劣&#xff0c;ECU常处于高温环境中&#xff1b;二是ECU所处的空间较为狭…...

视频汇聚平台:Liveweb视频流媒体平台视频监控系统解决方案

数字化技术在安防领域的广泛应用已经成为公安等重要执法部门的重要趋势&#xff0c;主要得益于无线网络通信技术和计算机技术的快速进步。传统的视频监控系统存在诸多局限&#xff0c;例如只能进行现场监视&#xff0c;报警信息传输简单&#xff0c;无法远距离传输视频信号&…...

通过解调使用正则化相位跟踪技术进行相位解包裹

1. 绪论 光学计量学通常使用光学干涉仪来测量各种物理量。1,2 根据应用的不同&#xff0c;可以使用多种类型的干涉仪&#xff0c;但它们的共同目标是产生一个由被测物理量调制的条纹图案。使用这种光束编码程序可以检测到的物理量范围非常广&#xff1a;深度测量、应变分析、温…...

VMware替代 | 双一流大学采用ZStack ZSphere虚拟化平台加速医学应用算法分析

某双一流大学医学部在面对日益增长的医学应用算法分析需求时&#xff0c;选择采用ZStack ZSphere虚拟化平台&#xff0c;以满足其高性能计算和GPU业务应用的迫切需求。该平台凭借其轻量化、卓越性能及易用性&#xff0c;成功解决了医学部在虚拟化及GPU应用场景中的挑战。随着平…...

UNIAPP框架uView初步集成与开发设计

uView UI&#xff0c;是uni-app生态最优秀的UI框架&#xff0c;全面的组件和便捷的工具会让您信手拈来&#xff0c;如鱼得水。本文章分享UNIAPP集成使用uView页面动态开发设计。 一、使用HBuilder X 直接导入插件&#xff0c;下载后重启 uView - DCloud 插件市场 二、配置样…...

C05S08-LVS负载均衡

一、LVS 1. LVS概述 LVS&#xff08;Linux Virtual Server、Linux虚拟服务&#xff09;是一种基于Linux系统集群的负载均衡方案&#xff0c;属于四层的负载均衡。 集群&#xff1a;将相同组件部署在不同的服务器上&#xff0c;提供统一的服务&#xff0c;以及同样的功能&…...

C 语言代码诗韵:数字功能的雅集华章

函数基本操作练习 主要内容&#xff1a; 本任务主要练习函数的申请、定义、调用等&#xff0c;主要包含以下功能&#xff1a; 1&#xff09;编写函数&#xff0c;输入一个整数&#xff0c;求各个数字之和&#xff1b; 2&#xff09;编写函数&#xff0c;计算1&#xff01;2&…...

ps案例制作

宣传海报 暖色调海报商品展示图...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅

目录 前言 操作系统与驱动程序 是什么&#xff0c;为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中&#xff0c;我们在使用电子设备时&#xff0c;我们所输入执行的每一条指令最终大多都会作用到硬件上&#xff0c;比如下载一款软件最终会下载到硬盘上&am…...