单元测试该怎么写

单元测试对于开发人员来说很熟悉,各种语言都提供了单元测试的框架,用于自动化执行单元测试并生成测试报告。它通常提供了一组API和工具,使开发人员能够编写和运行测试用例,比较预期行为和实际行为之间的差异,并准确地识别和报告错误。常见的单元测试框架包括JUnit、pytest、Mocha、Jasmine等。通过使用单元测试框架,开发人员可以更快地识别和修复代码中的问题,从而提高代码的质量和可靠性。除此之外, 还有一些工具提供了从代码直接生成单元测试代码的功能。因为这些框架和工具, 以及实际开发过程中的资源和时程的关系导致单元测试的编写较少的状况, 形成了一些对单元测试的误解或者说片面的理解, 类似:

  • 单元测试是由开发人员编写的
  • 单元测试是从编写的代码出发的

本篇以软件开发流程的完整视角来看看单元测试究竟是什么? 怎么写? 由谁写?

单元测试的定义

单元测试是一种软件测试方法,用于测试程序的最小单元——函数、方法或类的功能、性能和正确性。它是一种自动化测试,通过编写测试代码来验证程序的各个单元是否符合预期,从而提高代码的质量和可靠性。单元测试的目的在于降低代码的缺陷率,减少维护成本和提高代码的可维护性。

从这个定义中可以看到单元测试的对象是函数、方法、功能、性能等,这个定义也容易引起单元测试就是从代码出发的误解。那么单元测试究竟是否应该从代码出发呢?

单元测试的出发点

单元测试(Unit Test, UT)代码通常是从系统的规格和设计中产生的,而非直接从代码中产生。这是因为单元测试的目的是验证软件的单元(如函数,方法等)是否按照预定的规格或设计来执行。
以下是产生单元测试的一般过程:

  1. 理解软件规格: 对系统或软件应用的需求和规格有深入的理解是编写单元测试的关键。需要知道每个函数或方法的预期行为,包括输入、输出和边界条件等。
  2. 设计测试用例: 根据了解的规格,设计测试用例来覆盖所有可能的场景。这包括正常流程,错误流程,边界条件等。测试用例应能映射到特定的需求或规格,从而确保系统满足这些规格。
  3. 编写测试代码: 用选择的测试框架实现设计好的测试用例。
  4. 执行测试: 执行编写的测试并观察结果。如果所有的测试都通过,表示函数或方法满足其规格。如果有测试未能通过,需要对代码进行调试或修复,然后再次进行测试。
  5. 评估代码覆盖率: 使用代码覆盖率工具评估测试用例对代码的覆盖程度,确保所有代码路径都被合适的测试用例覆盖。
  6. 回归测试: 在每次更改或添加新代码后,运行所有的测试用例以确保新的更改没有破坏现有的功能。

总的来说,单元测试应从规格和设计出发,帮助验证代码是否按预期执行。
那么是否单元测试就必须要从规格和设计出发呢? 答案其实也不是绝对的,也可以从代码出发编写单元测试。

从代码出发编写单元测试

从代码出发编写单元测试是一种可行的方法,它被称为“开发之后测试”(Test-After Development),与“测试驱动开发”(TDD,Test-Driven Development)相对。也就是首先编写代码,然后针对这些代码编写对应的单元测试。

这种方法的优点是,能够确保代码在写单元测试时已经完成了,并且有可能覆盖到写代码时没考虑到的异常情况。它还有助于发现代码设计上的问题,因为编写测试可能需要对代码进行重构以使其可测试。

然而,这种方法也有几个潜在的缺点。

  • 首先,可能滞后于写测试,尤其是在项目时间紧张或者开发者讨厌写测试的情况下。
  • 其次,在编写的代码中可能已经潜入了错误,而这种方式在代码编写完之后才开始测试,所以比测试驱动开发(TDD)发现问题要慢。
  • 最后,编写测试可能需要对代码进行重构以使其更易于测试,这可能会浪费一定的时间。

总结一下: 不论你选择哪一种方式,最重要的是尽可能保证代码的覆盖率,并确保每次代码的修改或添加都有对应的测试用例进行验证。同时,要知道没有一种方法是在所有情况下都适用的,应根据项目的具体需求和团队的开发流程灵活选择

TDD模式的单元测试谁来写?

在许多软件开发团队或项目中,同一个人会写代码和对应的单元测试,这是一种被称为"测试驱动开发"(Test-Driven Development,TDD)的策略。在TDD中,开发者首先会编写测试,然后编写满足这些测试的最小代码。这种策略有助于确保代码的质量,并驱使开发者设计可测试的代码。

但这并不是唯一的策略。在另一些团队或项目中,可能会有专门的角色如质量保证(Quality Assurance)工程师来编写测试,或者开发者之间互相编写彼此代码的测试,这被称为"互相测试"(Peer testing)。

以下是使用不同策略的一些优缺点:

  • 开发者自己编写单元测试

    • 优点:开发者对自己的代码最为了解,能够编写能全面覆盖代码的测试。
    • 缺点:开发者可能会陷入一种偏见,只测试他们认为会失败、并且在开发时已经考虑过的流程。也有可能过度依赖测试来编写代码,导致代码过于复杂。
  • 其他开发者或 QA 工程师编写单元测试

    • 优点:其他编写测试的开发者或者 QA 工程师可能更有可能发现代码中的缺陷或错误,因为他们对代码没有偏见。
    • 缺点:他们可能对被测试的代码没有那么了解,所以可能编写的测试覆盖不够全面。

以上为一般性的理论讲解。在实际项目中,选择哪种策略取决于项目的规模、团队的大小和结构、项目的时间线和预算,以及其他各种因素。

测试驱动开发示例

测试驱动开发(Test-Driven Development,TDD)强调首先编写单元测试,然后再编写能够让测试通过的代码。下面的例子将使用这种方法来实现一个简单的 “加法” 函数。

假设我们的需求是需要一个加法函数,它接受两个整数作为参数,并返回它们的和。

使用测试驱动开发,我们首先编写测试,下面是AdderTest.java的内容:

import org.junit.Test;
import static org.junit.Assert.assertEquals;public class AdderTest {@Testpublic void testAdder() {Adder adder = new Adder();assertEquals(4, adder.add(2, 2));}
}

这个时候,我们还没有编写 Adder 类和 add() 方法,所以测试会失败,接下来,我们编写 Adder 类和 add() 方法来使得测试通过,下面是Adder.java的内容:

public class Adder {public int add(int a, int b) {return a + b;}
}

现在,再次运行单元测试。这次,由于Adder类和其add()方法已经实现,并且实现正确,所以测试应该能够通过。

这就是一个简单的测试驱动开发的例子。首先编写了单元测试,然后再编写实现相应功能的代码以满足测试的要求。这样做的好处是确保我们的代码满足了需求,同时代码是可测试的。

BDD-行为驱动开发

在敏捷开发中, 我们经常会听到一个词BDD-行为驱动开发, BDD是什么呢? 和TDD又是什么关系呢?

行为驱动开发(BDD)是一种敏捷软件开发方法,旨在提高软件质量和产品交付时间。BDD强调开发人员、业务人员和测试人员之间的协作,以确保软件实现满足需求和期望。BDD的核心理念是以用户的行为和期望为中心来定义软件的功能和行为,从而更好地理解和满足用户需求。

BDD的核心步骤包括:

  1. 定义用户故事:开发人员通过与客户和利益相关者合作,定义用户故事,明确软件的功能和期望。
  2. 定义场景:开发人员和测试人员一起定义场景,描述用户在特定情况下使用软件的期望行为。
  3. 编写测试用例:开发人员编写测试用例,验证场景中描述的行为和期望。
  4. 实现功能:开发人员编写代码实现软件功能。
  5. 运行测试:测试人员运行测试用例,并确保软件满足用户故事和场景的期望。
  6. 重复迭代:在开发过程中,重复以上步骤,确保软件的功能和行为符合用户期望,并最终交付高质量的软件产品。

BDD非常适合敏捷开发方法,因为它能够帮助软件开发团队更快、更好地满足客户和利益相关者的需求,并确保软件能够按时交付。

BDD(行为驱动开发)和TDD(测试驱动开发)都是一种敏捷软件开发中的测试方法。两者的主要区别在于关注点不同。

  • TDD关注的是单元测试,即在编写代码之前先编写测试代码,通过测试代码来驱动开发过程。TDD的重点在于确保代码质量和代码覆盖率。

  • BDD则更关注整体行为和用户需求。BDD的核心是给出一个需求或者场景,通过编写测试代码来验证行为是否符合需求和用户期望。BDD更加强调通过测试用例来描述软件行为,同时更加注重开发过程中的沟通和协作。

两者之间的关系是:BDD是TDD的延伸和完善。BDD除了关注代码的质量和代码覆盖率,还更加注重用户需求和行为,通过测试用例来描述软件行为,从而更好地实现软件的设计和开发。
在这里插入图片描述



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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

多线程锁-synchronized字节码分析

从字节码角度分析synchronized实现 javap -c(v附加信息) ***.class 文件反编译 synchronized同步代码块 >>>实现使用的是monitorenter和monitorexit指令 synchronized普通同步方法 >>>调用指令将会检查方法的ACC_SYNCHRONIZED访问标志是否被设置&#xf…

【数据结构-二叉树 九】【树的子结构】:树的子结构

废话不多说,喊一句号子鼓励自己:程序员永不失业,程序员走向架构!本篇Blog的主题是【子结构】,使用【二叉树】这个基本的数据结构来实现,这个高频题的站点是:CodeTop,筛选条件为&…

不同数据类型在单片机内存中占多少字节?

文章目录 前言一、不同编译器二、C51* 指针型 三、sizeof结构体联合体 前言 在C语言中,数据类型指的是用于声明不同类型的变量或者函数的一个广泛的系统。变量的类型决定了变量存储占用的空间 一、不同编译器 类型16位编译器大小32位编译器大小64位编译器大小char…

Kafka 简介之(学习之路)

正文 一、简介 1.1 概述 Kafka是最初由Linkedin公司开发,是一个分布式、分区的、多副本的、多订阅者,基于zookeeper协调的分布式日志系统(也可以当做MQ系统),常见可以用于web/nginx日志、访问日志,消息服务…

软件设计原则 1小时系列 (C++版)

文章目录 前言基本概念 Design Principles⭐单一职责原则(SRP) Single Responsibility PrincipleCode ⭐里氏替换原则(LSP) Liskov Substitution PrincipleCode ⭐开闭原则(OCP) Open Closed PrincipleCode ⭐依赖倒置原则(DIP) Dependency Inversion PrincipleCode ⭐接口隔离…

【抢先体验】开通使用 ChatGPT 语音版功能保姆级教程

大家好,我是苍何,一个土木转码的非典型程序员,也是一名技术管理者,同时也是 AI 应用的探索者。今天在视频号上看到和 ChatGPT 语音对话的视频,其声音的真实感太让人震撼了,于是也想去抢先体验一下 ChatGPT …

Centos7安装MongoDB7.xxNoSQL数据库|设置开机启动(骨灰级+保姆级)

一: mongodb下载 MongoDB 社区免费下载版 MongoDB社区下载版 [rootwww tools]# wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-7.1.0-rc4.tgz 二: 解压到指定目录 [rootwww tools]# mkdir -p /usr/local/mongodb [rootwww tools]# tar -zxvf mongodb-…

选择适合普通公司的项目管理软件

不管是打工人还是学生党都适合使用Zoho Projects项目管理软件。利用项目概览功能,将整体项目尽收眼底,作为项目管理者,项目日程、进度都可见,Zoho Projects项目管理APP助推项目每一环节的进展,更便于管理者设计项目的下…

ThingsBoard如何自定义tcp-transport

1、概述 很久没有更新了,一直忙于其他的事情,最近去搞了一个在ThingsBoard中自定义一个tcp-transport,用于连接使用tcp长连接的设备,目前使用tcp和mqtt协议连接服务端的设备还是很多,ThingsBoard的PE版提供了Integration是可以实现tcp的接入,但是CE版是没有提供接入tcp长…

【MySQL】基本查询(二)

文章目录 一. 结果排序二. 筛选分页结果三. Update四. Delete五. 截断表六. 插入查询结果结束语 操作如下表 //创建表结构 mysql> create table exam_result(-> id int unsigned primary key auto_increment,-> name varchar(20) not null comment 同学姓名,-> chi…

IO 之 操作properties属性文件

propreties文件: properties文件是一种用于存储配置信息的文本文件,通常以“.properties”为文件扩展名。它是一种简单的键值对格式,用于保存应用程序的配置参数。 在properties文件中,每一行都包含一个键值对,键和值…

HTTPS工作过程,国家为什么让http为什么要换成https,Tomcat在MAC M1电脑如何安装,Tomcat的详细介绍

目录 引言 一、HTTPS工作过程 二、Tomcat 在访达中找到下载好的Tomcat文件夹(这个要求按顺序) zsh: permission denied TOMCAT的各部分含义: 引言 在密码中一般是:明文密钥->密文(加密) &#xff…

Spring源码解析——IOC属性填充

正文 doCreateBean() 主要用于完成 bean 的创建和初始化工作,我们可以将其分为四个过程: 最全面的Java面试网站 createBeanInstance() 实例化 beanpopulateBean() 属性填充循环依赖的处理initializeBean() 初始化 bean 第一个过程实例化 bean在前面一篇…

复旦大学EMBA:揭秘科创企业,领略未来战略!

智能制造,国之重器。作为制造强国建设的主攻方向,智能制造的发展水平关系到我国未来制造业在全球的地位与影响力。发展智能制造,是加快建设现代化产业体系的重要手段,提升供给体系适配性的有力抓手,也是建设数字中国的…

【C++设计模式之状态模式:行为型】分析及示例

简介 状态模式(State Pattern)是一种行为型设计模式,它允许对象在内部状态改变时改变其行为,看起来就像是改变了其类。状态模式将对象的状态封装成不同的类,并使得对象在不同状态下有不同的行为。 描述 状态模式通过…

Android用户登录与数据存储:从权限请求到内外部存储的完整实践【完整实践步骤、外部存储、内部存储】

步骤 1: 登录页面布局 在 MainActivity 中实现用户登录功能&#xff0c;首先创建一个布局文件 activity_main.xml 包含用户名和密码的输入字段以及登录按钮。 <!-- activity_main.xml --> <LinearLayoutxmlns:android"http://schemas.android.com/apk/res/andr…

Qt之实现圆形进度条

在Qt自带的控件中&#xff0c;只有垂直进度条、水平进度条两种。 在平时做页面开发时&#xff0c;有些时候会用到圆形进度条&#xff0c;比如说&#xff1a;下载某个文件的下载进度。 展示效果&#xff0c;如下图所示&#xff1a; 实现这个功能主要由以下几个重点&#xff1a…

记录vue开发实例

封装的表格组件 <template><div><div style"width: 100%" v-if"showList"><el-table v-loading.lock"loading" :data"dataList":header-cell-style"{background: #F2FCFE,fontSize: 14px,color: #50606D}&…

因为在此系统上禁止运行脚本

问题&#xff1a; 解决办法&#xff1a; vue项目搭建中"因为在此系统上禁止运行脚本"报错&#xff0c;解决方法 - 你的剧本 - 博客园 (cnblogs.com)

详解链表oJ<反转链表,链表的中间节点及链表的回文>

hello&#xff0c;大家好&#xff0c;这里是Dark FlameMaster,今天和大家分享的是有关数据结构链表的几道题目&#xff0c;链表的中间节点&#xff0c;反转链表及判断链表是否为回文结构&#xff0c;放在一起讲解会印象更加深刻。 文章目录 一&#xff0c;链表的中间节点二&…