推荐轻量友好的.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开 ...
随机推荐
- A little problem for pt-pmp
https://bugs.launchpad.net/percona-toolkit/+bug/1320168 We use the pt-pmp (a variety for pmp !http:/ ...
- WinForm 批量设置指定控件中的控件状态
在开发中常遇到当点击某个按钮的时候,禁用文本框或按钮的的状态,以防止误操作,下面的代码是我已批量设置指定控件中的按钮状态的代码,同理可以延伸出很多操作. /// <summary> /// ...
- CentOS 编译安装 mysql
1.前期准备 1.1 环境说明: 操作系统: CentOS release 6.4 (Final) [查看命令 cat /etc/redhat-release ] mysql : mysql-5.6. ...
- 精确计算TFS中新增以及更改的代码行数
<configuration> <configSections> <section name="LOCTargets" type="Cons ...
- 十二、EnterpriseFrameWork框架核心类库之与EntLib结合
从本章开始对框架的讲叙开始进入核心类库的讲解,前面都是对框架外在功能讲解,让人有个整体的概念,知道包含哪些功能与对系统开发有什么帮助.以后多章都是讲解核心类库的,讲解的方式基本按照代码的目录结构,这样 ...
- hessian入门
hessian简介 Hessian是二进制的web service协议,官方网站提供Java.Flash/Flex.Python.C++..NET C#等实现.Hessian和Axis.XFire都能 ...
- java攻城狮之路(Android篇)--BroadcastReceiver&Service
四大组件:activity 显示. contentProvider 对外暴露自己的数据给其他的应用程序.BroadcastReceiver 广播接收者,必须指定要接收的广播类型.必须明确的指定acti ...
- 使用JavaScript判断用户是否为手机设备
最近在做微信服务号开发,其中遇到一个问题是微信服务号查看的个人的消息,如果点击在浏览器中查看(iOS中是在Safari中打开)应该是跳转到登录页面,因为页面需要从后台获取,因为需要服务端判断,如果是存 ...
- com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 2 of 2-byte
com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 2 of 2-byte ...
- Spring中加载配置文件的方式
原文:http://blog.csdn.net/snowjlz/article/details/8158560 Spring 中加载XML配置文件的方式,好像有3种, XML是最常见的Spring 应 ...