使用xUnit为.net core程序进行单元测试(1)

简介: 一. 导读 为什么要编写自动化测试程序(Automated Tests)? 可以频繁的进行测试 可以在任何时间进行测试,也可以按计划定时进行,例如:可以在半夜进行自动测试。 肯定比人工测试要快。

一. 导读

为什么要编写自动化测试程序(Automated Tests)?

  • 可以频繁的进行测试
  • 可以在任何时间进行测试,也可以按计划定时进行,例如:可以在半夜进行自动测试。
  • 肯定比人工测试要快。
  • 可以更快速的发现错误。
  • 基本上是非常可靠的。
  • 测试代码与生产代码紧密结合。
  • 使得开发团队更具有幸福感!

自动化测试的分类:

纵轴表示测试的深度,也就是说测试的细致程度。

横轴则表示测试的覆盖程度。

  • Unit Test 单元测试, 它可以测试一个类,或者一个类的某个功能,它具有很好的深度,但是对整个应用来说它不具备很好的覆盖面。
  • Integration Test 集成测试,它没有单元测试那么细致,但是具有相对较好的测试覆盖面。例如它可以测试功能的组合,以及像数据库或文件系统这样的外部资源等。
  • Subcutaneous Test 皮下测试,这种测试作用于UI层的下面一层,这也意味着它对整个应用来说有很好的覆盖率,但是深度欠佳。那一个MVC结构的应用来说,它就是针对刚好在Controller下面一层的测试,对于Web service来说,它就是对节点下面那层的测试。
  • UI测试,它的测试覆盖面很广,直接从UI层面进行测试,但是深度欠佳。

从速度来看 单元是最快的,而UI测试是最慢的。

从脆弱性来看 UI测试是最差的,程序修改后极有可能需要修改测试代码,而单元测试是最好的。

是测试行为还是测试私有方法(private method)?

        public void IncreaseHeartBeatRate()
        {
            HeartBeatRate = CalculateHeartBeatRate() + 2;
        }

        private int CalculateHeartBeatRate()
        {
            var random = new Random();
            return random.Next(1, 100);
        }

大多数情况下单元测试都应该是针对类的行为进行测试的,也就是public方法。当然也纯在不同的观点。

如果想要对private方法进行测试的话,是有很多缺点的:

  • 首先需要修改方法的访问限制需要从private改为public,这就破坏了面向对象的封装性。
  • 再者,这其实测试的是类的具体实现细节,而不是类的行为。如果我们想要对类的内部进行重构的话,就会破坏测试,导致测试也必须重构。如果必须对private方法进行测试,那么首先建议您把private修饰符改成internal,然后修改该项目(project)的AssemblyInfo.cs,它在项目的Debug或者Release文件夹下。代码如下:
[assembly: InternalsVisibleTo("Hospital.Tests")]

这表示Hospital.Tests这个测试项目可以访问该项目生产代码(production code)的internal方法。

测试的三个阶段 AAA

  • Arrange,这里做一些先决的设定。例如创建对象实例,数据,输入等等。
  • Act,在这里执行生产代码并返回结果。例如调用方法,或者设置属性(Properties)。
  • Assert,在这里检查结果。测试通过或者失败。

xUnit.net

官网:https://xunit.github.io/

xUnit是一个测试框架,可以针对.net/core进行测试。

测试项目需引用被项目从而对其进行测试,测试项目同时需要引用xUnit库。测试编写好后,用Test Runner来运行测试。Test Runner可以读取测试代码,并且会知道我们所使用的测试框架,然后执行,并显示结果。目前可用的Test Runner包括vs自带的Test Explorer,或者dotnet core命令行,以及第三方工具,例如resharper等等。

xUnit支持的平台:

.net full, .net core, .net standard, uwp, xamarin.

xUnit的例子:

        [Fact]
        public void TestIncreaseHeartBeatRate()
        {
            var patient = new Patient(); // Arrange
            patient.IncreaseHeartBeatRate(); // Act
            Assert.InRange(patient.HeartBeatRate, 40, 100); // Assert
        }

安装配置xUnit.net

a.使用Visual Studio 2017

首先建立一个C# library项目,叫Hospital(下面部分截图有个拼写错误,应该是Hospital),然后建立一个xUnit Test项目,叫Hospital.Tests:

 

可以看到Hospital.Tests已经包含里这几个库:

然后为Hospital.Tests添加到Hospital项目的引用。

b.使用.net core 命令行

首先把刚才建立的Hospital.Tests项目移除(目录需要手动删除).

然后打开项目位置:

按住shift打开命令行:

用命令行创建项目:

创建 Hospital.Tests目录,进入目录,使用命令dotnet new xunit创建xUnit单元测试项目。

添加项目的引用:

最后添加项目到解决方案:

回到VS界面,提示重新加载:

确认后,VS中解决方案结构如:

做第一个测试

对测试项目的文件名进行一些重构,编写以下代码,并进行Build:

从Test Explorer我们可以看到一个待测试的项目。

在这里,我们可以对测试项目进行分组和排序,如图:

想要运行所有的测试,就点击上面的Run All按钮。如果像运行单个测试,那么右击选择Run Selected Tests:

运行后,可以看到结果,Passed:

我们同样可以通过命令行来进行测试:

进入到Tests目录,执行 dotnet test命令,所有的测试都会被发现,然后被执行:

因为我们并没有在测试方法中写任何的Assert,所以测试肯定是通过的,但这个测试也是个无效的测试。

Assert

Assert做什么?Assert基于代码的返回值、对象的最终状态、事件是否发生等情况来评估测试的结果。Assert的结果可能是Pass或者Fail。如果所有的asserts都pass了,那么整个测试就pass了;如果有任何assert fail了,那么测试就fail了。

xUnit提供了以下类型的Assert:

  • boolean:True/False
  • String:相等/不等,是否为空,以..开始/结束,是否包含子字符串,匹配正则表达式
  • 数值型:相等/不等,是否在某个范围内,浮点的精度
  • Collection:内容是否相等,是否包含某个元素,是否包含满足某种条件(predicate)的元素,是否所有的元素都满足某个assert
  • Raised events:Custom events,Framework events(例如:PropertyChanged)
  • Object Type:是否是某种类型,是否某种类型或继承与某种类型

一个test里应该有多少个asserts?

一种建议的做法是,每个test方法里面只有一个assert。

而还有一种建议就是,每个test里面可以有多个asserts,只要这些asserts都是针对同一个行为就行。

第一个Assert

目标类:

    public class Patient
    {
        public Patient()
        {
            IsNew = true;
        }

        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string FullName => $"{FirstName} {LastName}";
        public int HeartBeatRate { get; set; }
        public bool IsNew { get; set; }

        public void IncreaseHeartBeatRate()
        {
            HeartBeatRate = CalculateHeartBeatRate() + 2;
        }

        private int CalculateHeartBeatRate()
        {
            var random = new Random();
            return random.Next(1, 100);
        }
    }

测试类:

    public class PatientShould
    {
        [Fact]
        public void HaveHeartBeatWhenNew()
        {
            var patient = new Patient();

            Assert.True(patient.IsNew);
        }
    }

运行测试:

 

结果符合预期,测试通过。

改为Assert.False()的话:

测试Fail。

String Assert

测试string是否相等

        [Fact]
        public void CalculateFullName()
        {
            var p = new Patient
            {
                FirstName = "Nick",
                LastName = "Carter"
            };
            Assert.Equal("Nick Carter", p.FullName);
        }

然后你需要Build一下,这样VS Test Explorer才能发现新的test。

运行测试,结果Pass:

同样改一下Patient类(别忘了Build一下),让结果失败:

从失败信息可以看到期待值和实际值。

StartsWith, EndsWith

        [Fact]
        public void CalculateFullNameStartsWithFirstName()
        {
            var p = new Patient
            {
                FirstName = "Nick",
                LastName = "Carter"
            };
            Assert.StartsWith("Nick", p.FullName);
        }

        [Fact]
        public void CalculateFullNameEndsWithFirstName()
        {
            var p = new Patient
            {
                FirstName = "Nick",
                LastName = "Carter"
            };
            Assert.EndsWith("Carter", p.FullName);e);
        }

Build,然后Run Test,结果Pass:

忽略大小写 ignoreCase

string默认的Assert是区分大小写的,这样就会失败:

可以为这些方法添加一个参数ignoreCase设置为true,就会忽略大小写:

包含子字符串 Contains

        [Fact]
        public void CalculateFullNameSubstring()
        {
            var p = new Patient
            {
                FirstName = "Nick",
                LastName = "Carter"
            };
            Assert.Contains("ck Ca", p.FullName);
        }

Build,测试结果Pass。

正则表达式,Matches

测试一下First name和Last name的首字母是不是大写的:

        [Fact]
        public void CalculcateFullNameWithTitleCase()
        {
            var p = new Patient
            {
                FirstName = "Nick",
                LastName = "Carter"
            };
            Assert.Matches("[A-Z]{1}{a-z}+ [A-Z]{1}[a-z]+", p.FullName);
        }

Build,测试通过。

数值 Assert

首先为Patient类添加一个property: BloodSugar。

    public class Patient
    {
        public Patient()
        {
            IsNew = true;
            _bloodSugar = 5.0f;
        }

        private float _bloodSugar;
        public float BloodSugar
        {
            get { return _bloodSugar; }
            set { _bloodSugar = value; }
        }
        ...

Equal:

        [Fact]
        public void BloodSugarStartWithDefaultValue()
        {
            var p = new Patient();
            Assert.Equal(5.0, p.BloodSugar);
        }

Build,测试通过。

范围, InRange:

首先为Patient类添加一个方法,病人吃饭之后血糖升高:

        public void HaveDinner()
        {
            var random = new Random();
            _bloodSugar += (float)random.Next(1, 1000) / 100; //  应该是1000
        }

添加test:

        [Fact]
        public void BloodSugarIncreaseAfterDinner()
        {
            var p = new Patient();
            p.HaveDinner();
            // Assert.InRange<float>(p.BloodSugar, 5, 6);
            Assert.InRange(p.BloodSugar, 5, 6);
        }

Build,Run Test,结果Fail:

可以看到期待的Range和实际的值,这样很好。如果你使用Assert.True(xx >= 5 && xx <= 6)的话,错误信息只能显示True或者False。

因为HaveDinner方法里,表达式的分母应该是1000,修改后,Build,Run,测试Pass。

下面是我的关于ASP.NET Core Web API相关技术的公众号--草根专栏:

目录
相关文章
|
14天前
|
开发框架 .NET 开发者
简化 ASP.NET Core 依赖注入(DI)注册-Scrutor
Scrutor 是一个简化 ASP.NET Core 应用程序中依赖注入(DI)注册过程的开源库,支持自动扫描和注册服务。通过简单的配置,开发者可以轻松地从指定程序集中筛选、注册服务,并设置其生命周期,同时支持服务装饰等高级功能。适用于大型项目,提高代码的可维护性和简洁性。仓库地址:&lt;https://github.com/khellang/Scrutor&gt;
37 5
|
2月前
|
测试技术 持续交付 API
深入挖掘探索.NET单元测试
【10月更文挑战第11天】
46 2
|
1月前
|
开发框架 .NET C#
在 ASP.NET Core 中创建 gRPC 客户端和服务器
本文介绍了如何使用 gRPC 框架搭建一个简单的“Hello World”示例。首先创建了一个名为 GrpcDemo 的解决方案,其中包含一个 gRPC 服务端项目 GrpcServer 和一个客户端项目 GrpcClient。服务端通过定义 `greeter.proto` 文件中的服务和消息类型,实现了一个简单的问候服务 `GreeterService`。客户端则通过 gRPC 客户端库连接到服务端并调用其 `SayHello` 方法,展示了 gRPC 在 C# 中的基本使用方法。
41 5
在 ASP.NET Core 中创建 gRPC 客户端和服务器
|
20天前
|
算法 Java 测试技术
Benchmark.NET:让 C# 测试程序性能变得既酷又简单
Benchmark.NET是一款专为 .NET 平台设计的性能基准测试框架,它可以帮助你测量代码的执行时间、内存使用情况等性能指标。它就像是你代码的 "健身教练",帮助你找到瓶颈,优化性能,让你的应用跑得更快、更稳!希望这个小教程能让你在追求高性能的路上越走越远,享受编程带来的无限乐趣!
70 13
|
22天前
|
开发框架 缓存 .NET
GraphQL 与 ASP.NET Core 集成:从入门到精通
本文详细介绍了如何在ASP.NET Core中集成GraphQL,包括安装必要的NuGet包、创建GraphQL Schema、配置GraphQL服务等步骤。同时,文章还探讨了常见问题及其解决方法,如处理复杂查询、错误处理、性能优化和实现认证授权等,旨在帮助开发者构建灵活且高效的API。
25 3
|
2月前
|
测试技术 API 开发者
精通.NET单元测试:MSTest、xUnit、NUnit全面解析
【10月更文挑战第15天】本文介绍了.NET生态系统中最流行的三种单元测试框架:MSTest、xUnit和NUnit。通过示例代码展示了每种框架的基本用法和特点,帮助开发者根据项目需求和个人偏好选择合适的测试工具。
46 3
|
1月前
|
开发框架 安全 .NET
.NET使用Moq开源模拟库简化单元测试
.NET使用Moq开源模拟库简化单元测试~
|
2月前
|
开发框架 JavaScript 前端开发
一个适用于 ASP.NET Core 的轻量级插件框架
一个适用于 ASP.NET Core 的轻量级插件框架
|
9天前
|
监控 JavaScript 测试技术
postman接口测试工具详解
Postman是一个功能强大且易于使用的API测试工具。通过详细的介绍和实际示例,本文展示了Postman在API测试中的各种应用。无论是简单的请求发送,还是复杂的自动化测试和持续集成,Postman都提供了丰富的功能来满足用户的需求。希望本文能帮助您更好地理解和使用Postman,提高API测试的效率和质量。
49 11
|
1月前
|
JSON Java 测试技术
SpringCloud2023实战之接口服务测试工具SpringBootTest
SpringBootTest同时集成了JUnit Jupiter、AssertJ、Hamcrest测试辅助库,使得更容易编写但愿测试代码。
65 3

热门文章

最新文章