通义灵码实践教程——单元测试

news/2024/10/21 16:33:43

通义灵码加持的单元测试实践

本文首先讲述了什么是单元测试、单元测试的价值、一个好的单元测试所具备的原则,进而引入如何去编写一个好的单元测试,通义灵码是如何快速生成单元测试的。

什么是单元测试?

单元测试是一种软件测试方法,通过编写代码来验证应用程序中最小的可测试单元(如单个函数、方法或类)的正确性。通常,单元测试由开发人员在功能实现过程中或完成后编写,其目的是确保每个最小可测试单元都能按照设计预期正常工作。

单元测试的价值

单元测试的价值主要体现在提高软件质量和可靠性,‌确保代码在修改或重构后仍然能够正常运行。‌单元测试的优势包括:

  • 提高代码质量:‌通过发现代码中的错误和漏洞,‌从而提高代码的质量和可靠性。‌
  • 提高开发效率:‌在开发过程中及时发现问题,‌减少开发周期和成本。‌
  • 便于重构和维护:‌确保代码在重构和维护过程中不会出现新的错误和漏洞。‌
  • 有助于团队协作:‌作为团队成员之间的沟通和协作工具,‌提高团队的协作效率和质量。‌

此外,‌单元测试还可以让软件故障尽早被发现,‌避免故障遗留到后期由于定位修复难度带来的更大损失。‌它的可回归性为软件提供了一层安全防护网,‌为软件后续的重构和修改提供了安全保障。‌单元测试还为软件单元如何被使用提供了天然的代码样例使用手册。

遵循的原则

好的单元测试就像空气(AIR)一样感觉不到,但在测试质量的保障上,却是非常关键的。好的单元测试宏观上来说,具有自动化(A)、独立性(I)、可重复执行(R)的特点。

  • A: Automatic(自动化):单元测试应能被自动化执行,以便在代码更改时快速确认新加入的代码没有破坏已有功能,通常情况下会将单测接入到持续集成中,每当代码有变更时都会通过持续集成自动触发单元测试。
  • I: Independent(独立性):每个单元测试应当是独立的,不能依赖于其他测试的执行顺序或结果。这也要求单测的测试颗粒度必须足够小,只有这样才能满足独立性。
  • R: Repeatable(可重复执行):好的单元测试在同样的条件下,每次运行应当给出相同的结果。它不应依赖于外部因素(如网络、数据库或文件系统),需要对这些外部的依赖进行正确的mock 。

除此之外,好的单测还必须要满足有明确的断言,执行速度快,边界测试充分,覆盖率高等特点。只有满足这些条件的单测才是好的单测,好的单元测试是对代码质量保障至关重要的一环。

如何编写单元测试?

下面以Java语言为例来介绍如何编写单元测试,总体遵循以下几个步骤:

拆分详细的测试用例

考虑分支条件

在编写单元测试时,需要考虑代码中的所有分支。分支包括if、else、switch语句等,每个分支都需要单独测试。例如:

public String classifyNumber(int number) {if (number < 0) {return "negative";} else if (number == 0) {return "zero";} else {return "positive";}
}

在上述代码中,有三个分支需要测试:

  • number<0。
  • number==0。
  • number>0。

针对每个分支,都需要编写一个测试用例。

寻找边界条件

除了分支,还需要考虑边界条件。例如,对于上述分类函数,边界值是-1、0和1。边界条件测试可以找出可能潜在的问题,确保代码在极限条件下也能正常工作。

制定统一的单测规范

命名规范

单元测试类通常采用 类名Test的形式。例如,如果要测试一个Calculator类,则单元测试类可以命名为CalculatorTest。单元测试方法的命名应当描述具体要测试的内容。例如:

public class CalculatorTest {@Testpublic void testAddition() {// 测试内容}@Testpublic void testSubtraction() {// 测试内容}
}

存放路径

一般情况下,单元测试类存放的位置在与被测试类相同包名的下面,但在不同的目录中。在标准的 Maven 项目结构中,源代码放在src/main/java,单元测试代码放在src/test/java。

src/main/java/com/example/Calculator.java
src/test/java/com/example/CalculatorTest.java

选择合适的单测框架

Java 常用的单元测试框架有JUnit和Mockito,下面将围绕如何使用这两种框架编写基本的单元测试:

JUnit 测试框架

JUnit是Java语言中最著名的单元测试框架。它简洁易用,提供了丰富的注解和断言。

  1. 添加JUnit依赖(以Maven为例):
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope>
</dependency>
  1. 编写单元测试:
import org.junit.Test;
import static org.junit.Assert.*;public class CalculatorTest {@Testpublic void testAddition() {Calculator calculator = new Calculator();assertEquals(5, calculator.add(2, 3));}
}

Mockito 测试框架

Mockito是一个强大的模拟框架,用于创建虚拟对象,简化单元测试,特别是在测试不易创建的依赖对象时非常有用。

  1. 添加Mockito依赖:
<dependency><groupId>org.mockito</groupId><artifactId>mockito-core</artifactId><version>3.11.2</version><scope>test</scope>
</dependency>
  1. 编写单元测试:
import static org.mockito.Mockito.*;
import org.junit.Test;public class UserServiceTest {@Testpublic void testGetUser() {UserService userService = new UserService();UserRepository mockRepo = mock(UserRepository.class);when(mockRepo.findUserById(1)).thenReturn(new User(1, "John Doe"));userService.setUserRepository(mockRepo);User user = userService.getUserById(1);assertNotNull(user);assertEquals("John Doe", user.getName());}
}

如何使用通义灵码快速生成单测

在大多数开发者的编程习惯中,通常采用Test Later的方法进行单元测试,即首先编写好代码,然后再为代码编写相应的单元测试。在此背景下,利用通义灵码生成单元测试显得尤为便捷。以下列举几种使用通义灵码生成单元测试的方式。

手工选中代码方式生成

在 IDE 编辑区中,通过通义灵码选中某段代码来生成单测,选中代码后,在灵码的问答框内,通过 /generate unit test来生成与选中的代码对应的单元测试。

说明:使用/generate unit test这个命令时,可以在输入框追加更多的信息,来生成更符合开发者需要的测试用例,如需要支持JUnit5或采用Mockito进行Mock,就可以采用 /generate unit testJUnit5Mockito这样的方式,后面两个关键词被当作前面命令的参数,这样的使用方式,同样适用于其他命令。

使用快捷按钮方式生成

通义灵码插件在每个方法签名的上面都会有一个小图标,单击图标后会弹出相应的命令菜单,选择生成单元测试。

也可以选择要生成的代码块,然后单击右键来选择生成单元测试功能。

采纳单元测试

单测代码生成完毕后,在问答区的代码块右上角,会有三个选项,分别是插入代码,复制和新建文件:

  • 插入代码:会将当前生成的单测代码插入到当前打开的文件中。
  • 复制:即复制代码块的代码,由用户自行选择将代码复制到哪个文件中。
  • 新建文件:会按照Java单测的规范,新生成一个单测类文件,放到指定的目录中(对应单测方法文件所在的test目录下),如果已经存在同名的单测文件,需要用户自主确认是否覆盖原文件。

单测生成追问

如果您对当前生成的单测代码不满意(需要使用特定的单测框架或者生成更多的单测方法),只需在问答区中的输入框输入相应的文本进行追问即可,或者也可以单击预置的单测追问Tag,如示例中追问的Tag :Retry、Use Mockito、Use Spring Test和Explain code,进行追问,直到生成您满意的单测代码为止。

说明:一般根据代码生成的单元测试,会枚举常用的测试用例,并不会遍历所有的用例。如果您觉得生成的用例不足,建议先采纳当前生成的几个用例,放到测试文件当中。然后,切换到测试文件中,采用代码续写的方式,通义灵码会帮助您续写新的测试用例。

结语

单元测试是重要的编程实践,为编码过程搭建质量围栏。同时,采用测试驱动开发实践中的Test First ,能够显著推动代码设计的演变。通义灵码,可以极大降低单元测试框架的搭建和测试用例编写的工作量。同时,使用通义灵码对单元测试用例保鲜,可以显著提升编码质量。

用通义灵码维护遗留代码的正确姿势

本文首先介绍了遗留代码的概念,并对遗留代码进行了分类。针对不同类型的遗留代码,提供了相应的处理策略。此外,本文重点介绍了通义灵码在维护遗留代码过程中能提供哪些支持。

什么是遗留代码

  • 与过时技术相关的代码:
    • 与不再受支持的操作系统或软件库相关的代码。
    • 依赖于已淘汰的技术栈或编程语言的代码。
  • 为兼容老旧功能而保留的代码:
    • 在现代软件中为了兼容旧版本功能而保留的代码片段。
    • 为了确保向后兼容性而不得不保留的代码。
  • 缺乏文档和维护的代码:
    • 没有良好文档支持的旧代码。
    • 缺乏现代开发实践(如单元测试、代码审查等)的代码。

解决遗留代码的方法

解决遗留代码有以下三种常见的处理方法:

根据上述描述,补充单元测试是一种有效解决遗留代码问题的方法。然而,这种方法仍然存在一些问题:

  • 大量遗留代码缺少单元测试,并且由于代码间的复杂依赖关系,进行测试的成本非常高。
  • 具体的衡量标准却不够清晰,无法定义好的单元测试。
  • 哪些代码需要添加单元测试?

单元测试常见的误区

  • 缺乏断言的假单元测试:开发者可能会采取仅调用函数而不进行断言的方式,以提高覆盖率指标,导致了许多无效的单元测试。
  • 把单元测试当成白盒测试:一些观点将单元测试归类为白盒测试,但实际上应将其视为针对函数签名的黑盒测试。
  • 依赖真实环境的单元测试:阻碍单元测试的主要因素包括惰性和依赖环境配置。若不使用Stub或Mock解除对外部环境(如网络IP、数据库)的依赖,单元测试将难以达到FIRST原则(快速、独立、可重复、自我验证、及时性)。

选择性的进行单元测试

单元测试除了带来收益外,本身也会产生一定的成本。如果从收益与成本的角度分析遗留代码,将有助于明确为遗留代码补充单元测试的策略,此策略被称为选择性单元测试。那么,如何界定成本与收益呢?

遗留代码单元测试的成本收益象限分类

针对遗留代码的单元测试,可以根据其成本和收益进行象限分类。根据下图,对分类标准和各象限进行详细说明:

分类标准

  • X轴(成本):代码依赖程度越高,测试成本越大。
  • Y轴(收益):代码复杂度越高,质量收益越大。

四个象限

圈复杂度与依赖的概念理解

  • 圈复杂度(Cyclomatic Complexity):衡量代码中逻辑分支的数量。
  • 扇入(Fan-In):直接调用该模块的上级模块的个数,扇入大表示模块的复用程度高。
  • 扇出(Fan-out):一个模块直接调用的其他模块的数量,扇出大表示该模块依赖其他模块越多。

不同类型代码的处理策略

根据上述的分析,遗留代码的处理策略就变得十分明确:

  • 算法类代码(Algorithms Code):生成单元测试。
  • 协调类代码(Coordinators Code):进行接口测试。
  • 复杂代码(Overcomplicated Code):寻找合适的机会进行重构。
  • 琐碎代码(Trivial Code):不做处理。

使用通义灵码处理遗留代码

1. 了解项目工程

在维护一个工程的遗留代码,首先可通过 @workspace 功能了解整个工程的目的及其涉及的各个模块。

2. 对不同类型代码进行处理

针对算法类(Algorithms)代码生成单元测试

选中需要基于生产代码进行代码生成的部分。在生成时,请注意所需的框架及Mock等依赖信息,可以通过生成单元测试命令后追加相关信息进行补充。如 /generate unit testingCppUTest。

一般而言,基于现有代码生成的单元测试用例数量通常较为有限。如果对单元测试的测试场景及用例数量有具体要求,可以在新生成的单元测试文件中,通过测试函数的续写方式生成更多的单元测试。在续写过程中,通义灵码将尽可能遵循已有用例,以此作为上下文进行参考。

针对协调类代码(Coordinators)进行接口测试

对于协调类代码而言,单元测试并不是一种理想的解决方案,由于存在过多的依赖,测试成本显著提高。针对此类代码,应该采用接口测试或功能测试的方式进行覆盖,然而在编写自动化测试用例时,开发者常常会遇到相关问题。因此,可以通过通义灵码,快速掌握并理解测试框架。

针对用例的编写,可以选择相应的被测函数,并在问答区中直接提问:基于Robot Framework生成以下代码的测试用例。沿着这一思路,同样可以实现相应的Keywords等内容。

超复杂的代码(Overcomplicated Code)找机会进行重构

针对超复杂的代码,可以使用通义灵码的 /generate optimization 命令,以获得针对所选代码的优化建议。代码审查与优化将从语法问题、异常改进、代码整洁度、安全性及风险等多个维度给出相应的优化建议。

针对复杂遗留代码的优化,并不建议开发者们盲目进行全面的优化和重构。遗留代码的变更可能会带来巨大的风险。因此,开发者应根据具体情况,在合适的机会,遵守童子军法则,进行重构和优化。在这一过程中,通义灵码也将为您提供有力支持。

结语

以上便是在处理遗留代码时可参考的实践。处理遗留代码需要深入代码的复杂结构,细致地追踪每一个可能的分支节点。在这一过程中,除了识别并修复潜在的缺陷外,还必须在有限的时间内完成所有任务。为了避免这一局面的发生,最佳的策略是预防代码的腐化,善用工具,并在编写初期遵循良好的编程原则。

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

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

相关文章

2024秋软工实践 银河战舰队展示与选题报告

作业所属课程 班级的链接作业要求 https://edu.cnblogs.com/campus/fzu/SE2024/homework/13290作业的目标 开发一个基于LLM大模型接口的软件,为传统的软件赋予全新的体验和功能。团队名称 银河战舰团队成员学号-名字 102202129-林伟宏 102202131-林鑫 102202109-木合塔拉提 10…

geojson的下载与展示

下载地址:https://datav.aliyun.com/portal/school/atlas/area_selecto 展示地址:https://l7editor.antv.antgroup.com/

VMware低版本打开高版本虚拟机

前言全局说明VMware低版本打开高版本虚拟机一、说明 环境: Windows 11 家庭版 23H2 22631.3737二、注意修改前,备份虚拟机文件 为了数据安全,最好不要手动修改虚拟机配置信息 最好使用对应版本创建的虚拟机三、版本对应 https://www.cnblogs.com/wutou/p/17712402.html四、修…

【验证码识别专栏】大炮打麻雀 — CLIP 图文多模态模型,人均通杀 AIGC 六、九宫格验证码

前言 近期有粉丝私信,不知道如何训练某讯系点选验证码,之前星球群也有不少粉丝讨论相关问题,为满足粉丝们的需求,本文将对这型验证码的训练进行讲解, 文末可以下载相关的工具,包括 文章配套标注工具 + 文章配套训练代码 + 部分学习数据集(少量类目,仅供学习使用,不设计…

数据库—多表查询、事务

1.多表查询: 例:点击查看代码 # 创建部门表 CREATE TABLE dept( did INT PRIMARY KEY AUTO_INCREMENT, dname VARCHAR(20) );# 创建员工表 CREATE TABLE emp ( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(10), gender CHAR(1), -- 性别 salary DOUBLE, -- 工资 join_d…

021 天气案例

@click后面也可以写一些简单语句,这样就不用配置methods了

通义灵码操作指南——插件配置指南

点击链接,立即下载通义灵码插件:https://tongyi.aliyun.com/lingma/ 通义灵码支持在 Visual Studio Code、JetBrains IDEs 中修改常用快捷键、进行行间生成的启用/禁用等功能开关配置。 Visual Studio Code 中配置通义灵码 准备工作 如果需要在 Visual Studio Code 中使用通义…

1200PLC通过NODERED,将数据发布到阿里云物联网平台

配置要求:1,电脑上需要安装有博图软件,我这里使用的是TIA Portal V16版本 2,电脑上需要安装NODE_RED 3,已经有阿里云物联网平台账号。新建PLC项目,编写PLC程序, *新建PLC项目,我这里硬件为cpu1214,dcdc_R| | | | | ---- | ---- | ---- | | | …