千家信息网

怎样使用xUnit为.net core程序进行单元测试

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,怎样使用xUnit为.net core程序进行单元测试,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一. 导读为什么要编写自动化测试程序
千家信息网最后更新 2026年11月03日怎样使用xUnit为.net core程序进行单元测试

怎样使用xUnit为.net core程序进行单元测试,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

一. 导读

为什么要编写自动化测试程序(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(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。

看完上述内容,你们掌握怎样使用xUnit为.net core程序进行单元测试的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注行业资讯频道,感谢各位的阅读!

测试 项目 方法 结果 代码 单元 命令 运行 程序 就是 深度 目录 类型 行为 元素 内容 大小 对象 建议 文件 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 手冲咖啡和咖啡机区别 上海挚品互联网科技 唐信互联网科技 互联网科技logo 天下捷融互联网科技 中正互联网科技招聘 安控科技rtu产品工业互联网 互联网科技大奖都有哪些公司 山东子淼互联网科技有限公司 南通创西澳互联网科技有限公司 厦门江牛科技互联网 下一代互联网重大应用科技园 南京一网一红互联网科技有限公司 福州德业互联网科技 长沙渺峰互联网科技有限公司 科技和互联网行业的特点 广西泛欧互联网科技有限公司 第三届互联网大会安防黑科技 数字科技和互联网金融哪个好 杭州科技互联网公司有哪些 互联网科技公司排名 老年人脱离互联网科技的作文 移动互联网科技股 呼和浩特新华互联网科技学院 想开互联网科技公司怎么样 启辰互联网科技 中天科技中国工业互联网 图游互联网科技 中国主要互联网科技公司 武汉亿视互联网科技有限公司
0