推荐轻量友好的.NET测试断言工具Shouldly
Shouldly是一个轻量的断言(Assertion)框架,用于补充.NET框架下的测试工具。Shouldly将焦点放在当断言失败时如何简单精准的给出很好的错误信息。
Shouldly在GitHub的开源地址:https://github.com/shouldly/shouldly
Shouldly的官方文档:http://docs.shouldly-lib.net/
为什么要Shouldly?
我们知道通常测试代码中一个断言是这样写的:
Assert.That(contestant.Points, Is.EqualTo());
当断言失败的时候,我们会得到这样的信息:
Expected but was
这样的信息让人烦恼的是,它够简练,但显然信息不够充分,可读性不高。
Shouldly充分利用了.NET框架的扩展方法,提供了更友好的处理方式。
用Shouldly编写的断言是这样的:
contestant.Points.ShouldBe();
其中ShouldBe是一个扩展方法,也可以认为是一个易于理解的语法词汇。当断言失败的时候,我们会得到这样的信息:
contestant.Points should be but was
Shouldly的优势
下面的一个例子将两种断言方式放在一起,通过对比更容易发现Shouldly的好处:
Assert.That(map.IndexOfValue("boo"), Is.EqualTo()); // -> Expected 2 but was 1
map.IndexOfValue("boo").ShouldBe(); // -> map.IndexOfValue("boo") should be 2 but was 1
Shouldly使用ShouldBe语句中的变量来报告错误,这使得更容易诊断。
另一个例子,如果你需要比较两个集合,采用Shouldly写法如下:
(new[] { , , }).ShouldBe(new[] { , , });
显然断言会失败,因为这两个集合并不相同。但Shouldly不仅如此,它会告诉你两个集合的差异所在:
should be
[, , ]
but was
[, , ]
difference
[, , **]
如果你想检查一个特殊的方法调用,它会或者不会抛出异常,它可以简单地这样写:
Should.Throw<ArgumentOutOfRangeException>(() => widget.Twist(-));
这样就可以接触到异常,借此帮助你调试出潜在的异常来源。
详细用法
Shouldly断言框架提供了相等、迭代、动态变量、字符串、字典、任务/异步,以及异常等多方面的支持。要详细的了解这些可以访问Shouldly的官方文档:http://docs.shouldly-lib.net/
后续的断言例子基于下面的范例类:
namespace Simpsons
{
public abstract class Pet
{
public abstract string Name { get; set; } public override string ToString()
{
return Name;
}
}
} namespace Simpsons
{
public class Cat : Pet
{
public override string Name { get; set; }
}
} namespace Simpsons
{
public class Dog : Pet
{
public override string Name { get; set; }
}
} namespace Simpsons
{
public class Person
{
public string Name { get; set; }
public int Salary { get; set; } public override string ToString()
{
return Name;
}
}
}
Equality 相等
ShouldBe
[Test]
public void ShouldBe()
{
var theSimpsonsCat = new Cat() { Name = "Santas little helper" };
theSimpsonsCat.Name.ShouldBe("Snowball 2");
}
失败信息:
Shouldly.ChuckedAWobbly :
theSimpsonsCat.Name
should be
"Snowball 2"
but was
"Santas little helper"
ShouldNotBe
[Test]
public void ShouldNotBe()
{
var theSimpsonsCat = new Cat() { Name = "Santas little helper" };
theSimpsonsCat.Name.ShouldNotBe("Santas little helper");
}
失败信息:
Shouldly.ChuckedAWobbly :
theSimpsonsCat.Name
should not be
"Santas little helper"
but was
"Santas little helper"
ShouldBeOfType
[Test]
public void ShouldBeOfType()
{
var theSimpsonsDog = new Cat() { Name = "Santas little helper" };
theSimpsonsDog.ShouldBeOfType<Dog>();
}
失败信息:
Shouldly.ChuckedAWobbly :
theSimpsonsDog
should be of type
Simpsons.Dog
but was
Simpsons.Cat
Enumberable 迭代
用于对列表集合进行断言
ShouldAllBe
[Test]
public void IEnumerable_ShouldAllBe_Predicate()
{
var mrBurns = new Person() { Name = "Mr.Burns", Salary=};
var kentBrockman = new Person() { Name = "Homer", Salary = };
var homer = new Person() { Name = "Homer", Salary = };
var millionares = new List<Person>() {mrBurns, kentBrockman, homer}; millionares.ShouldAllBe(m => m.Salary > );
}
失败信息:
Shouldly.ChuckedAWobbly :
millionares
should all be an element satisfying the condition
(m.Salary > )
but does not
ShouldContain
[Test]
public void IEnumerable_ShouldContain()
{
var mrBurns = new Person() { Name = "Mr.Burns", Salary=};
var kentBrockman = new Person() { Name = "Homer", Salary = };
var homer = new Person() { Name = "Homer", Salary = };
var millionares = new List<Person>() {kentBrockman, homer}; millionares.ShouldContain(mrBurns);
}
失败信息:
Shouldly.ShouldAssertException :
millionares
should contain
Mr.Burns
but does not
ShouldContain(Predicate)
[Test]
public void IEnumerable_ShouldContain_Predicate()
{
var homer = new Person() { Name = "Homer", Salary = };
var moe = new Person() { Name = "Moe", Salary=};
var barney = new Person() { Name = "Barney", Salary = };
var millionares = new List<Person>() {homer, moe, barney}; // Check if at least one element in the IEnumerable satisfies the predicate
millionares.ShouldContain(m => m.Salary > );
}
失败信息:
Shouldly.ChuckedAWobbly :
millionares
should contain an element satisfying the condition
(m.Salary > )
but does not
Dynamic 动态对象
ShouldHaveProperty
[Test]
public void DynamicShouldHavePropertyTest()
{
var homerThinkingLikeFlanders = new ExpandoObject();
DynamicShould.HaveProperty(homerThinkingLikeFlanders, "IAmABigFourEyedLameO");
}
失败信息:
Shouldly.ChuckedAWobbly :
Dynamic Object
"homerThinkingLikeFlanders"
should contain property
"IAmABigFourEyedLameO"
but does not.
String 字符串
ShouldMatch
[Test]
public void ShouldMatch()
{
var simpsonDog = new Dog() { Name = "Santas little helper" };
simpsonDog.Name.ShouldMatch("Santas [lL]ittle Helper");
}
失败信息:
Shouldly.ChuckedAWobbly :
simpsonDog.Name
should match
"Santas [lL]ittle Helper"
but was
"Santas little helper"
ShouldBeNullOrEmpty
[Test]
public void ShouldBeNullOrEmpty()
{
var anonymousClanOfSlackJawedTroglodytes = new Person() {Name = "The Simpsons"};
anonymousClanOfSlackJawedTroglodytes.Name.ShouldBeNullOrEmpty();
}
失败信息:
Shouldly.ChuckedAWobbly :
anonymousClanOfSlackJawedTroglodytes.Name
should be null or empty
Dictionary 字典
ShouldNotContainKey
[Test]
public void ShouldNotContainKey()
{
var websters = new Dictionary<string, string>();
websters.Add("Chazzwazzers", "What Australians would have called a bull frog."); websters.ShouldNotContainKey("Chazzwazzers");
}
失败信息:
Shouldly.ChuckedAWobbly :
Dictionary
"websters"
should not contain key
"Chazzwazzers"
but does
ShouldContainKeyAndValue
[Test]
public void ShouldNotContainKey()
{
var websters = new Dictionary<string, string>();
websters.Add("Chazzwazzers", "What Australians would have called a bull frog."); websters.ShouldNotContainKey("Chazzwazzers");
}
失败信息:
Shouldly.ChuckedAWobbly :
Dictionary
"websters"
should not contain key
"Chazzwazzers"
but does
Task/Async 任务/异步
CompleteIn
[Test]
public void CompleteIn()
{
var homer = new Person() { Name = "Homer", Salary = };
var denominator = ;
Should.CompleteIn(() =>
{
Thread.Sleep();
var y = homer.Salary / denominator;
}, TimeSpan.FromSeconds());
}
失败信息:
System.TimeoutException : The operation has timed out.
Exceptions 异常
ShouldThrow
[Test]
public void ShouldThrowFuncOfTask()
{
var homer = new Person() { Name = "Homer", Salary = };
var denominator = ;
Should.Throw<DivideByZeroException>(() =>
{
var task = Task.Factory.StartNew(() => { var y = homer.Salary/denominator; });
return task;
});
}
失败信息:
Shouldly.ChuckedAWobbly :
Should
throw
System.DivideByZeroException
but does not
ShouldNotThrow(Func<Task>)
这个方法支持异步方法,并且会等待操作执行直到完成。
[Test]
public void ShouldNotThrowFuncOfTask()
{
var homer = new Person() { Name = "Homer", Salary = };
var denominator = ;
Should.NotThrow(() =>
{
var task = Task.Factory.StartNew(() => { var y = homer.Salary/denominator; });
return task;
});
}
失败信息:
Shouldly.ChuckedAWobbly :
Should
not throw
System.DivideByZeroException
but does
推荐轻量友好的.NET测试断言工具Shouldly的更多相关文章
- .NET测试断言工具Shouldly
.NET测试断言工具Shouldly .NET测试 Shouldly在GitHub的开源地址:https://github.com/shouldly/shouldly Shouldly的官方文档:ht ...
- 推荐轻量高效无依赖的开源JS插件和库
目录 图片 布局 音频视频 编辑器 轮播图 弹出层 表单 存储 动画 时间 其它 CDN 图片 baguetteBox.js - 是一个简单易用的响应式图像灯箱效果脚本.demo Lightgalle ...
- RestTemplate---Spring提供的轻量Http Rest 风格API调用工具
前言 今天在学习Spring Cloud的过程中无意发现了 RestTemplate 这个Spring 提供的Http Rest风格接口之间调用的模板工具类,感觉比Apache提供的HttpClien ...
- 五款轻量型bug管理工具横向测评
五款轻量型bug管理工具横向测评 最近正在使用的本地bug管理软件又出问题了,已经记不清这是第几次了,每次出现问题都要耗费大量的时间精力去网上寻找解决方案,劳心劳力.为了避免再次出现这样的情况,我决定 ...
- 推荐一个简单、轻量、功能非常强大的C#/ASP.NET定时任务执行管理器组件–FluentScheduler定时器
在C#WINFORM或者是ASP.NET的WEB应用程序中,根据各种定时任务的需求,比如:每天的数据统计,每小时刷新系统缓存等等,这个时候我们得应用到定时器这个东东. .NET Framework有自 ...
- Furatto – 轻量,友好的响应式前端开发框架
Furatto 是一个基于 Bootstrap & Foundation 的前端开发框架,用于快速开发网站.这个框架采用流行的扁平化设计和响应式设计.除了布局和网格之外,所有的主要元素都有预定 ...
- 推荐一款轻量小众却高效免费开源windows热键脚本语言Autohotkey
写在前面的话 Autohotkey是一款轻量小众但高效免费开源的windows热键脚本语言,游戏操纵.鼠标操作.键盘快捷重定义,快捷短语等等,只有你想不到,没有它做不到,神器中的神器呀,相见恨晚. 安 ...
- Vue.js:轻量高效的前端组件化方案
转发一篇尤老师对vue.js的介绍,了解vue.js的来龙去脉.不过现在已经是2.0了,也有添加一些新的东西,当然有些东西也改了. Vue.js:轻量高效的前端组件化方案 Vue.js 是我在2014 ...
- 基于netty轻量的高性能分布式RPC服务框架forest<下篇>
基于netty轻量的高性能分布式RPC服务框架forest<上篇> 文章已经简单介绍了forest的快速入门,本文旨在介绍forest用户指南. 基本介绍 Forest是一套基于java开 ...
随机推荐
- JMir——Java版热血传奇2之资源文件与地图
我虽然是90后,但是也很喜欢热血传奇2(以下简称“传奇”)这款游戏. 进入程序员行业后自己也对传奇客户端实现有所研究,现在将我的一些研究结果展示出来,如果大家有兴趣的话不妨与我交流. 项目我托管到co ...
- SetHandleInformation设置内核对象标志
当父进程创建子进程时,子进程将继承父进程的内核对象.这时如果要控制子进程使用父进程的内核对象.可以使用 SetHandleInformation设置. BOOL SetHandleInformatio ...
- SQL1159 Initialization error with DB2 .NET Data Provider, reason code 7(问题补充)
SQL1159 Initialization error with DB2 .NET Data Provider, reason code 7 需要注册GAC,修改注册表 IBM官方方案: http: ...
- Objective-C Polymorphism
#import <Foundation/Foundation.h> @interface Shape : NSObject { CGFloat area; } -(void)printAr ...
- 如何对excel进行列查重
学习了excel函数:countif.表达式:COUNTIF(数据区域,条件),作用:对数据区域内符合条件单元格计数 具体应用 在“姓名”(列A)后插入一列(列B),在B2单元格输入公式“=IF(CO ...
- java中JTextPane使输出字符到指定的宽度换行,并将垂直滚动条的位置移动到输出的最后位置
SimpleAttributeSet set = new SimpleAttributeSet(); Document doc = tp.getStyledDocument(); FontMetric ...
- Membership三步曲
http://www.cnblogs.com/jesse2013/p/membership-part1.html http://www.cnblogs.com/jesse2013/p/membersh ...
- java io系列01之 "目录"
java io 系列目录如下: 01. java io系列01之 "目录" 02. java io系列02之 ByteArrayInputStream的简介,源码分析和示例(包括 ...
- Tips1:用 Export Package选项来分享你的成果
如果你不是一个人工作,你可能需要和其他人共享一个工程文件,Unity工程文件中的一些关键元素默认是隐藏的,因此通过复制Assets文件夹的方法并不完善.Unity自带的UnityPackage格式的文 ...
- android resources使用总结
http://developer.android.com/guide/topics/resources/more-resources.html http://developer.android.com ...