C#中实现单元测试的示例流程_MSTest测试项目

一、单元测试简介

1.1、单元测试简介

        在《单元测试艺术》一书中对于单元测试的定义是:【一个单元测试是一段代码,这段代码调用一个工作单元(指:调用软件中的一个方法,这个方法执行过程中所发生的所有行为以及最后产生的结果的总和),并检验该工作单元的一个具体的结果。如果关于这个结果的最终假设是错误的,单元测试就失败了;一个单元测试的范围可以小到一个方法,大到多个类

1.2、单元测试的意义

        要注意:引入单元测试或有单元测试并不能证明代码质量好(应根据项目情况进行调整适配,比如优先考虑核心模块),单元测试并不是越多越好(不要忽视引入代码测试以及无效的测试所带来的维护成本【如:增加开发的时间、增加人员成本】,毕竟资源是有限的)。

        若不考虑时间成本,还是希望各位可以为代码编写高效可靠的单元测试,毕竟这对提升代码质量有帮助;而单元测试具有如下意义:

1、通过单元测试用例确保的功能,不会在后续的迭代过程中产生Bug;

2、在重构模块时,因为有单元测试覆盖,也可以大胆去做;

3、可以通过单元测试模块了解模块具体功能和预期;

4、提高代码质量,降低耦合;

二、单元测试示例流程

2.1、打开VisualStudio创建项目

1、使用VisualStudio创建一个跨平台的控制台项目(取名为:Test_UnitTest),如下图所示:

2、新建一个名为: BankAccount 的银行账户类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace test_UnitTest
{public class BankAccount{private readonly string m_customerName;private double m_balance;public BankAccount(string customerName,double balance){m_customerName = customerName;m_balance = balance;Console.WriteLine($"\n初始的余额是【{Balance}】");}public string CustomerName{get { return m_customerName; }}public double Balance{get { return m_balance; } }/// <summary>/// 借钱出去/// </summary>/// <param name="amout">金额</param>/// <exception cref="ArgumentOutOfRangeException"></exception>public void Debit(double amout){if (amout>m_balance){throw new ArgumentOutOfRangeException("amount");}if (amout<0){throw new ArgumentOutOfRangeException("amount");}m_balance += amout;Console.WriteLine($"借钱【{amout}】出去后的余额是【{Balance}】");}public const string DebitAmountExceedsBalanceMessage = "当前借出的金额超过当前的余额";public const string DebitAmountLessThanZeroMessage = "当前借出的金额小于0";/// <summary>/// 借钱出去/// </summary>/// <param name="amout">金额</param>/// <exception cref="ArgumentOutOfRangeException"></exception>public void Debit2(double amout){if (amout > m_balance){throw new ArgumentOutOfRangeException("amount",amout, DebitAmountExceedsBalanceMessage);}if (amout < 0){throw new ArgumentOutOfRangeException("amount",amout, DebitAmountLessThanZeroMessage);}m_balance += amout;Console.WriteLine($"借钱【{amout}】出去后的余额是【{Balance}】");}/// <summary>/// 贷款进来/// </summary>/// <param name="amout">金额</param>/// <exception cref="ArgumentOutOfRangeException"></exception>public void Credit(double amout){if (amout<0) {throw new ArgumentOutOfRangeException("amout");}m_balance += amout;Console.WriteLine($"贷款【{amout}】进来后的余额是【{Balance}】");}}//Class_end
}

3、运行该银行账户类

namespace test_UnitTest
{internal class Program{static void Main(string[] args){Console.WriteLine("Hello, World!");BankAccount ba = new BankAccount("张三", 11.99);ba.Credit(5.77);ba.Debit(11.22);Console.WriteLine($"当前账户的余额是 ${ba.Balance}");Console.ReadLine();}}
}

        到目前为止程序是没有报错的;但是仔细查看我们就会发现一个问题,借钱出去后,我们的银行账户应该是余额减少的;但是我们的程序却显示余额增加了,这明显是错误的;关于这样的类似错误我们可以通过单元测试来避免,修复这个Bug。

2.2、创建单元测试项目

2.2.1、新增单元测试项目,并且添加项目引用

 

2.2.2、创建单元测试类BankAccountTest.cs

将默认的UnitTest1.cs类修改名称为【BankAccountTest.cs】,默认的测试类示例如下

using Microsoft.VisualStudio.TestTools.UnitTesting;namespace BankTests
{[TestClass]public class BankAccountTests{[TestMethod]public void TestMethod1(){}}
}

其中【TestClass】标识该类是一个单元测试类;【TestMethod】标识该方法是一个单元测试方法。

2.2.3、编写一个单元测试的示例方法

单元测试方法的必备要求
序号
1必须使用 [TestMethod] 特性进行修饰
2方法必须返回 void
3单元测试方法必须不能含有参数
 Assert.AreEqual、Assert.IsTrue 等方法经常用于单元测试Assert Class (Microsoft.VisualStudio.TestTools.UnitTesting) | Microsoft Learn

①分析:编写单元测试方法以验证 BankAccount 类的 Debit 方法的行为,则至少需要检查三种行为:

  • 如果借方金额大于余额,该方法将引发 ArgumentOutOfRangeException 。

  • 如果借方金额小于零,该方法会引发 ArgumentOutOfRangeException。

  • 如果借方金额有效,该方法会从帐户余额中减去该借方金额。

②第一个单元测试方法:验证是否从帐户中提取了正确的有效金额(即小于帐户余额且大于零);将以下方法添加到该 BankAccountTests 类:

        [TestMethod]//验证借出指定的金额后是否与预期的金额相等public void Debit_WithValidAmount_UpdatesBalance(){double beginningBalance = 11.99;    //初始金额double debitAmount = 4.55;          //借出去的金额数量double expected = 7.44;             //进出金额后期望剩余的金额数量BankAccount account = new BankAccount("张三", beginningBalance);account.Debit(debitAmount);double actual = account.Balance;//判断是否相等[若不相等则抛出异常]Assert.AreEqual(expected, actual, 0.001, "该账户的金额并没有正确的借出去!!!");}

③生成并运行单元测试和解决错误

首先生成解决方案

然后选择顶部的【测试】-->【运行所有测试】结果如下: 

 最后根据单元测试的错误提示排查是由于调用账户的借出金额后的余额与期望的余额不一致导致报错,我们需要排查【account.Debit()】方法,需要将【account.Debit()】方法的 m_balance += amout;修改为 m_balance -= amout;后保存重新【运行所有测试】即可通过单元测试),如下图所示:

BankAccountTest.cs银行账户的完整单元测试类内容如下:

具体的每步细节可以查看如下的链接

C# 单元测试教程 - Visual Studio (Windows) | Microsoft Learn了解如何使用托管代码的 Microsoft 单元测试框架和 Visual Studio 测试资源管理器创建、运行和自定义单元测试系列。icon-default.png?t=N7T8https://learn.microsoft.com/zh-cn/visualstudio/test/walkthrough-creating-and-running-unit-tests-for-managed-code?view=vs-2022

using test_UnitTest;namespace UnitTest
{[TestClass]public class BankAccountTest{[TestMethod]//验证借出指定的金额后是否与预期的金额相等public void Debit_WithValidAmount_UpdatesBalance(){double beginningBalance = 11.99;    //初始金额double debitAmount = 4.55;          //借出去的金额数量double expected = 7.44;             //进出金额后期望剩余的金额数量BankAccount account = new BankAccount("张三", beginningBalance);account.Debit(debitAmount);double actual = account.Balance;//判断是否相等[若不相等则抛出异常](运行测试后发现抛出了【该账户的金额并没有正确的借出去!!!】的异常;我们此时需要排查【account.Debit()】方法,//需要将【account.Debit()】方法的 m_balance += amout;修改为 m_balance -= amout;后重新运行即可通过单元测试)Assert.AreEqual(expected, actual, 0.001, "该账户的金额并没有正确的借出去!!!");}[TestMethod]//验证借出去的金额小于零时的行为是否正确(即:应该报错)public void Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange(){double beginningBalance = 11.99;double debitAmount = -100;BankAccount bankAccount = new BankAccount("张三",beginningBalance);//使用 ThrowsException 方法断言已引发正确的异常。 除非 ArgumentOutOfRangeException 已引发,否则该方法将导致测试失败。//如果在借方金额小于零时,临时修改测试方法以引发更通用的 ApplicationException,则测试将正确运行,即测试将失败。Assert.ThrowsException<System.ArgumentOutOfRangeException>(() => bankAccount.Debit(debitAmount));}[TestMethod]//验证借出去的金额大于余额时的行为是否正确(即:应该报错)public void Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange(){double beginningBalance = 11.99;double debitAmount =20.0;BankAccount bankAccount = new BankAccount("张三", beginningBalance);//使用 ThrowsException 方法断言已引发正确的异常。 除非 ArgumentOutOfRangeException 已引发,否则该方法将导致测试失败。//如果在借方金额大于余额时,临时修改测试方法以引发更通用的 ApplicationException,则测试将正确运行,即测试将失败。Assert.ThrowsException<System.ArgumentOutOfRangeException>(() => bankAccount.Debit(debitAmount));}[TestMethod]//该测试方法解决【没有办法知道哪个条件(amount > m_balance 或 amount < 0)导致在测试期间引发异常。//我们只知道在方法中引发了一个 ArgumentOutOfRangeException。//更理想的情况是,如果我们知道是 BankAccount.Debit 中的哪个条件导致引发异常(amount > m_balance 或 amount < 0),//这样就可以确信我们的方法可以正确合理地检查其自变量。】public void Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange2(){// Arrangedouble beginningBalance = 11.99;double debitAmount = 20.0;BankAccount account = new BankAccount("张三", beginningBalance);// Acttry{account.Debit2(debitAmount);}catch (System.ArgumentOutOfRangeException e){// AssertStringAssert.Contains(e.Message, BankAccount.DebitAmountExceedsBalanceMessage);}}[TestMethod]//该测试方法解决【测试方法不会处理它原本应该处理的所有情况。//如果所测试的方法 Debit 在 debitAmount 大于余额(或小于零)时未能引发 ArgumentOutOfRangeException,则该测试方法通过。//这样并不好,因为如果未引发异常,则希望测试方法失败。这是测试方法中的一个 bug。//要解决该问题,在测试方法末尾添加 Assert.Fail 断言,处理未引发异常的情况。】public void Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange3(){// Arrangedouble beginningBalance = 11.99;double debitAmount = 20.0;BankAccount account = new BankAccount("张三", beginningBalance);// Acttry{account.Debit2(debitAmount);}catch (System.ArgumentOutOfRangeException e){// AssertStringAssert.Contains(e.Message, BankAccount.DebitAmountExceedsBalanceMessage);return;}Assert.Fail("未引发预期的异常");}}//Class_end
}

三、单元测试资料

Visual Studio 中的测试工具 - Visual Studio (Windows) | Microsoft Learn了解如何使用功能 Visual Studio 来测试代码。icon-default.png?t=N7T8https://learn.microsoft.com/zh-cn/visualstudio/test/?view=vs-2022

单元测试入门 - Visual Studio (Windows) | Microsoft Learn使用 Visual Studio 定义和运行单元测试,使代码保持正常运行并在客户之前找到错误和缺陷。icon-default.png?t=N7T8https://learn.microsoft.com/zh-cn/visualstudio/test/getting-started-with-unit-testing?view=vs-2022&tabs=dotnet%2Cmstest 单元测试基础知识 - Visual Studio (Windows) | Microsoft Learn了解 Visual Studio 测试资源管理器如何提供灵活而高效的方法来运行单元测试并查看其结果。icon-default.png?t=N7T8https://learn.microsoft.com/zh-cn/visualstudio/test/unit-test-basics?view=vs-2022#write-your-testsC# 单元测试教程 - Visual Studio (Windows) | Microsoft Learn了解如何使用托管代码的 Microsoft 单元测试框架和 Visual Studio 测试资源管理器创建、运行和自定义单元测试系列。icon-default.png?t=N7T8https://learn.microsoft.com/zh-cn/visualstudio/test/walkthrough-creating-and-running-unit-tests-for-managed-code?view=vs-2022

Assert Class (Microsoft.VisualStudio.TestTools.UnitTesting) | Microsoft LearnA collection of helper classes to test various conditions within unit tests. If the condition being tested is not met, an exception is thrown.icon-default.png?t=N7T8https://learn.microsoft.com/zh-cn/dotnet/api/microsoft.visualstudio.testtools.unittesting.assert?view=visualstudiosdk-2022

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

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

相关文章

Day05-循环高级和数组

循环高级 1.无限循环 概念&#xff1a; 又叫死循环。循环一直停不下来。 for格式&#xff1a; for(;;){System.out.println("循环执行一直在打印内容"); } 解释&#xff1a; 初始化语句可以空着不写&#xff0c;表示循环之前不定义任何的控制变量。 条件判断…

maven中relativepath标签的含义

一 relative标签的含义 1.1 作用 这个<parent>下面的<relativePath>属性&#xff1a;parent的pom文件的路径。 relativePath 的作用是为了找到父级工程的pom.xml;因为子工程需要继承父工程的pom.xml文件中的内容。然后relativePath 标签内的值使用相对路径定位…

ChatGPT 在机器学习中的应用

办公室里一个机器人坐在人类旁边&#xff0c;Artstation 上的流行趋势&#xff0c;美丽的色彩&#xff0c;4k&#xff0c;充满活力&#xff0c;蓝色和黄色&#xff0c; DreamStudio出品 一、介绍 大家都知道ChatGPT。它在解释机器学习和深度学习概念方面也非常高效&#xff0c;…

matplotlib绘图实现中文宋体的两种方法(亲测)

方法一&#xff1a;这种方法我没有测试。 第一步 找宋体字体 &#xff08;win11系统&#xff09; 2.matplotlib字体目录&#xff0c;如果不知道的话&#xff0c;可以通过以下代码查询&#xff1a; matplotlib.matplotlib_fname() 如果你是Anaconda3 安装的matplotlib&#x…

uni-app打包iOS ipa文件后不上架App store为用户提供下载解决过程记录

写在前面&#xff0c;itms-services协议是什么 itms-services协议是苹果提供的一种让iOS应用在用户设备上无线安装或升级的协议。 具体来说: itms-services表示iOS应用无线安装服务的URL方案,格式为:itms-services://?actiondownload-manifest&urlMANIFEST_URL其中MANIF…

Apache Beam 2.50.0发布,该版本包括改进功能和新功能

导读我们很高兴向您介绍 Beam 的新版本 2.50.0。该版本包括改进功能和新功能。请查看此版本的下载页面。 亮点 Spark 3.2.2 被用作 Spark 运行程序的默认版本&#xff08;#23804&#xff09;。Go SDK 新增默认本地运行程序&#xff0c;名为 Prism&#xff08;#24789&#xff0…

基于web的学校二手书城系统/二手书交易系统

摘 要 本文论述了学校二手书城系统的设计和实现&#xff0c;该网站从实际运用的角度出发&#xff0c;运用了计算机网站设计、数据库等相关知识&#xff0c;网络和Mysql数据库设计来实现的&#xff0c;网站主要包括用户注册、用户登录、浏览图书、搜索图书、查看图书并进行购买…

大数据Flink(八十五):Window TVF 支持多维数据分析

文章目录 Window TVF 支持多维数据分析 一、Grouping Sets 二、​​​​​​​Rollup

【数据库】存储引擎InnoDB、MyISAM、关系型数据库和非关系型数据库、如何执行一条SQL等重点知识汇总

目录 存储引擎InnoDB、MyISAM的适用场景 关系型和非关系型数据库的区别 MySQL如何执行一条SQL的 存储引擎InnoDB、MyISAM的适用场景 InnoDB 是 MySQL 默认的事务型存储引擎&#xff0c;只有在需要它不支持的特性时&#xff0c;才考虑使用其它存储引擎。实现了四个标准的隔…

Vue2+ElementUI 静态首页案例

源码 <template><div class"app-container home"><el-row type"flex" justify"space-around" class"row-bg"><el-card class"box-card cardDiv1"><el-col :span"5"><div clas…

软考-操作系统

/4操作系统的作用 进程 进程的概念 进程是程序的一次执行过程&#xff0c;没有程序就没有进程 进程可有多个线程&#xff0c;线程可共享资源 进程的两个基本属性&#xff1a; 可拥有资源的独立单位可独立调度和分配资源的基本单位 线程可共享&#xff1a; 内存地址空间代码…

自定义Unity组件——AudioManager(音频管理器)

需求描述 在游戏开发中&#xff0c;音频资源是不可或缺的&#xff0c;通常情况下音频资源随机分布&#xff0c;各个音频的操作和管理都是各自负责&#xff0c;同时对于音频的很多操作逻辑都是大同小异的&#xff0c;这就造成了许多冗余代码的堆叠&#xff0c;除此之外在获取各类…

Axure RP9 引入eCharts图表

一、 ECharts 地址&#xff1a;https://echarts.apache.org/zh/index.html 概述&#xff1a;一个基于 JavaScript 的开源可视化图表库 提供了很多图标样式案例 二、 Axure引入eCharts图表步骤 步骤一&#xff1a;打开Axure&#xff0c;添加矩形元素&#xff0c;调整矩形所…

WorkPlus私有化部署IM即时通讯平台,构建高效安全的局域网办公环境

随着数字化转型的加速&#xff0c;政府机构与企业对高效、安全的即时通讯和协作工具的需求日益增长。企业微信和钉钉作为当前市场上较为常见的通讯工具&#xff0c;虽然在一定程度上满足了企业内部协作的需求&#xff0c;但仍存在一些问题&#xff0c;如数据安全性、私有化部署…

静态路由+BFD实例

项目拓扑与项目需求 项目需求 ① 主链路为电信&#xff0c;电信链路出故障时&#xff0c;业务数据流量切换到联通链路 实验步骤 步骤1&#xff1a;设备重命名以及IP地址的配置 设备 接口编号 IP地址 AR1 G0/0/0 10.0.13.1/24 G0/0/1 10.0.14.1/24 AR2 G0/0/0 10.0…

IntelliJ IDEA快速查询maven依赖关系

1.在Maven窗口中点击Dependencies->show Dependencies 2.得到依赖关系图 此时原有快捷键Ctrlf可以查询jar包&#xff0c;如果没有查询菜单出来则设置快捷键方式为 File->Settings->Keymap->搜索栏输入find->在Main Menu下Edit下Find下Find双击算则Add keyboard…

项目任务管理上的一些总结

1. 开发任务管理现状&#xff1a; 1&#xff1a;基于禅道进行任务派发&#xff0c;缺少任务统计&#xff0c;进度上只能以“来不及”、“进度正常”、“进度延后”等模糊字眼。 2&#xff1a;“感觉”工作效率不高了&#xff0c;工作量是否饱和&#xff0c;任务投入产出偏差多…

vue3中$refs使用调整

前言&#xff1a; vue3环境 在vue2环境中&#xff0c;可以直接通过this.$refs获取模块&#xff1b;在vue3环境中&#xff0c;通用以下两种方式获取&#xff1a; 1、通过声明ref进行获取&#xff1b; import { ref} from vue; const logoForm ref(); console.log(logoForm.va…

NSDT孪生场景编辑器系统介绍

一、产品背景 数字孪生的建设流程涉及建模、美术、程序、仿真等多种人才的协同作业&#xff0c;人力要求高&#xff0c;实施成本高&#xff0c;建设周期长。如何让小型团队甚至一个人就可以完成数字孪生的开发&#xff0c;是数字孪生工具链要解决的重要问题。考虑到数字孪生复杂…

go语言unsafe.Pointer与uintptr

以下内容来源go语言圣经 1、unsafe.Pointer&#xff0c;相当于c语言中的void *类型的指针&#xff0c;如果需要运算需要转成uintptr类型的指针 2. uintptr uintptr是一个无符号的整型&#xff0c;它可以保存一个指针地址。 它可以进行指针运算。 uintptr无法持有对象, GC不把…