单元测试知识总结

news2024/12/18 0:55:48

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

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 {

  @MockBean
  EmployeeService employeeService;

  @Autowired
  MockMvc mockMvc;

  @Test
  public 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 {

  @InjectMocks
  EmployeeService service;

  @Mock
  EmployeeRepository dao;

  @BeforeEach
  public void init() {
    MockitoAnnotations.openMocks(this);
  }

  @Test
  void 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);

    //test
    List<Employee> empList = service.findAll();

    assertEquals(3, empList.size());
    verify(dao, times(1)).findAll();
  }

  @Test
  void 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 {

  @Autowired
  EmployeeRepository employeeRepository;

  @Test
  public 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2261322.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前后端跨域问题(CROS)

前端 在src中创建util文件&#xff0c;写request.js文件&#xff1a; request.js代码如下&#xff1a; import axios from axios import { ElMessage } from element-plus;const request axios.create({// baseURL: /api, // 注意&#xff01;&#xff01; 这里是全局统一加…

【数据结构——查找】顺序查找(头歌实践教学平台习题)【合集】

目录&#x1f60b; 任务描述 相关知识 测试说明 我的通关代码: 测试结果&#xff1a; 任务描述 本关任务&#xff1a;实现顺序查找的算法。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;1.根据输入数据建立顺序表&#xff0c;2.顺序表的输出&#xff0c;…

Android 车载虚拟化底层技术-Kernel 5.15 -Android13(multi-cards)技术实现

系列文章请扫点击如下链接&#xff01; Android Display Graphics系列文章-汇总 本文主要包括部分&#xff1a; 一、Android13的Kernel 5.15版本 1.1 Kernel 5.15 情况说明 1.2 前置条件 二、QCM61*5 plane配置 2.1 multi-card配置 2.2 移植msm-lease 2.3 配置信息确认…

【FFmpeg】FFmpeg 内存结构 ⑥ ( 搭建开发环境 | AVPacket 创建与释放代码分析 | AVPacket 内存使用注意事项 )

文章目录 一、搭建开发环境1、开发环境搭建参考2、项目搭建 二、AVPacket 创建与释放代码分析1、AVPacket 创建与释放代码2、Qt 单步调试方法3、单步调试 - 分析 AVPacket 创建与销毁代码 三、AVPacket 内存使用注意事项1、谨慎使用 av_init_packet 函数2、av_init_packet 函数…

C# DLT645 97/07数据采集工具

电表模拟器 97协议测试 07协议测试 private void btnSend_Click(object sender, EventArgs e) {string addr txtAddr.Text.Trim();string data txtDataFlg.Text.Trim();byte control 0x01;switch (cmbControl.SelectedIndex){case 0: control (byte)0x01; break;// 97协议c…

颜色代码表: 一站式配色方案设计工具集网站

大家好&#xff0c;我是一名设计师&#xff0c;同时也是一名开发者。平时的工作中&#xff0c;相信很多设计师和我一样经常遇到一个问题&#xff1a;设计配色方案时&#xff0c;工具太分散了。寻找颜色搭配灵感需要去一个网站&#xff0c;颜色代码转换要开另一个&#xff0c;检…

Android显示系统(13)- 向SurfaceFlinger提交Buffer

Android显示系统&#xff08;01&#xff09;- 架构分析 Android显示系统&#xff08;02&#xff09;- OpenGL ES - 概述 Android显示系统&#xff08;03&#xff09;- OpenGL ES - GLSurfaceView的使用 Android显示系统&#xff08;04&#xff09;- OpenGL ES - Shader绘制三角…

WebSocket 与 Server-Sent Events (SSE) 的对比与应用

目录 ✨WebSocket&#xff1a;全双工通信的利器&#x1f4cc;什么是 WebSocket&#xff1f;&#x1f4cc;WebSocket 的特点&#x1f4cc;WebSocket 的优点&#x1f4cc;WebSocket 的缺点&#x1f4cc;WebSocket 的适用场景 ✨Server-Sent Events (SSE)&#xff1a;单向推送的轻…

Mysql 深度分页查询优化

Mysql 分页优化 1. 问题根源 问题&#xff1a; mysql在数据量大的时候&#xff0c;深度分页数据偏移量会增大&#xff0c;导致查询效率越来越低。 问题根源&#xff1a; 当使用 LIMIT 和 OFFSET 进行分页时&#xff0c;MySQL 必须扫描 OFFSET LIMIT 行&#xff0c;然后丢弃前…

SpringBoot - 动态端口切换黑魔法

文章目录 关键技术点核心原理Code 关键技术点 利用 Spring Boot 内嵌 Servlet 容器 和 动态端口切换 的方式实现平滑更新的方案&#xff0c;关键技术点如下&#xff1a; Servlet 容器重新绑定端口&#xff1a;Spring Boot 使用 ServletWebServerFactory 动态设置新端口。零停…

linux(CentOS8)安装PostgreSQL16详解

文章目录 1 下载安装包2 安装3 修改远程连接4 开放端口 1 下载安装包 官网下载地址&#xff1a;https://www.postgresql.org/download/ 选择对应版本 2 安装 #yum源 yum -y install wget https://download.postgresql.org/pub/repos/yum/reporpms/EL-8-x86_64/pgdg-redha…

spring学习(spring-bean实例化(无参构造与有参构造方法实现)详解)

目录 一、spring容器之bean的实例化。 &#xff08;1&#xff09;"bean"基本概念。 &#xff08;2&#xff09;spring-bean实例化的几种方式。 二、spring容器使用"构造方法"的方式实例化bean。 &#xff08;1&#xff09;无参构造方法实例化bean。 &#…

ElasticSearch学习5

基本Rest命令说明&#xff1a; method url地址 描述 PUT&#xff08;创建,修改&#xff09; localhost:9200/索引名称/类型名称/文档id 创建文档&#xff08;指定文档id&#xff09; POST&#xff08;创建&#xff09; localhost:9200/索引名称/类型名称 创建文档&…

分享本周所学——三维重建算法3D Gaussian Splatting(3DGS)

大家好&#xff0c;欢迎来到《分享本周所学》第十二期。本人是一名人工智能初学者&#xff0c;刚刚读完大二。前几天自学了一下3D Gaussian Splatting&#xff08;3DGS&#xff09;&#xff0c;觉得非常有意思。写这篇文章主要是因为网上大部分关于3DGS的文章都比较晦涩&#x…

【中工开发者】鸿蒙商城app

这学期我学习了鸿蒙&#xff0c;想用鸿蒙做一个鸿蒙商城app&#xff0c;来展示一下。 项目环境搭建&#xff1a; 1.开发环境&#xff1a;DevEco Studio2.开发语言&#xff1a;ArkTS3.运行环境&#xff1a;Harmony NEXT base1 软件要求&#xff1a; DevEco Studio 5.0.0 Rel…

【Qt】按钮类控件:QPushButton、QRadioButton、QCheckBox、ToolButton

目录 QPushButton 例子&#xff1a; QRadioButton 例子&#xff1a; 按钮的常见信号函数 单选按钮分组 例子&#xff1a; QCheckButton 例子&#xff1a; QToolButton QWidget的常见属性及其功能对于它的派生类控件都是有效的(也就是Qt中的各种控件)&#xff0c;包括…

UI框架DevExpress XAF v24.2新功能预览 - .NET Core / .NET增强

DevExpress XAF是一款强大的现代应用程序框架&#xff0c;允许同时开发ASP.NET和WinForms。DevExpress XAF采用模块化设计&#xff0c;开发人员可以选择内建模块&#xff0c;也可以自行创建&#xff0c;从而以更快的速度和比开发人员当前更强有力的方式创建应用程序。 在上文中…

ArrayList源码分析、扩容机制面试题,数组和List的相互转换,ArrayList与LinkedList的区别

目录 1.java集合框架体系 2. 前置知识-数组 2.1 数组 2.1.1 定义&#xff1a; 2.1.2 数组如何获取其他元素的地址值&#xff1f;&#xff08;寻址公式&#xff09; 2.1.3 为什么数组索引从0开始呢&#xff1f;从1开始不行吗&#xff1f; 3. ArrayList 3.1 ArrayList和和…

阿里云服务器手动部署LNMP环境【官方文档注意事项】

这是官方文档 注意&#xff1a; 要添加安全组&#xff0c;端口为80。否则最后用浏览器访问公网IP没有结果。 Mysql密码策略要求密码至少包含一个大写字母、一个小写字母、一个数字和一个特殊字符&#xff0c;并且密码总长度至少为 8 个字符。sudo mysqladmin -uroot -p<ol…

Invalid default value for ‘gender‘,mysql在idea中字符集设置,default

默认值default创建错误的&#xff0c;设置数据库字符集 我的错误&#xff1a;Invalid default value for ‘gender’ -- 修改数据库字符集 alter database db01 charset utf8;