前言

  今天与同事在讨论.Net下测试框架的时候,说到NUnit等大多数测试框架的SetUp以及TearDown方法并不是显得那么完美,所以在公司内部的项目中采用了Xunit框架。那么究竟是什么样的原因,让我们放弃了大多数框架都在用的Nunit或MSTest框架呢?

1. Xunit简介

  首先奉上马丁大叔2006年对XUnit介绍的文章,http://www.martinfowler.com/bliki/Xunit.html

  Xunit其实是JUnit的衍生版,最开始是应用在Smalltalk中,其目的是支持持续集成,关于单元测试等相关内容可以参考我之前TDD系列文章,这里不做过多的介绍,只是介绍Why we choose Xunit。

  GitHub地址:https://github.com/xunit/xunit

  官方文档:http://xunit.github.io/

2. Xunit简单Demo

如此简单:

提示:需要通过NuGet下载xunit.net和xunit.visualstudio这两个安装包,然后启动“Test Explorer”运行测试,详情请参考这里

3. Xunit对比Nunit的优点

这部分内容参考了官方文章以及一些自己对测试框架的场景的理解,如有错误之处,还请指出。

3.1 每个测试单一实例的讨论,SetUp以及TestFixtureSetUp

  请参考马丁大师对单一实例的论述:http://martinfowler.com/bliki/JunitNewInstance.html,文章指出:对于测试缓存或每次测试之前重新实例化对象,这种做法是值得商榷的。虽然其有利于对象的调用,而且基本不用考虑对象回收的问题(仅当在TearDown中回收了资源),但这样仍然不符合绝对意义上的“对象隔离”原则。而且有些变量是只需全局实例化一次(在Nunit框架中要使用TestFeature创建),虽然这样也能满足需求,但是程序中还是有很多这种框架的特性需要熟悉,相比没有这些框架(指没有SetUp和TestFixtureSetUp)的语法来讲跟不方便一些,当然这些仅仅是一些思考。

  同时,James Newkrik也在文章中提到,与其在SetUp中初始化更多的参数,破坏单一职责的原则,另外加上每回测试都要回顾SetUp和TearDown方法所执行的内容,倒不如将其放在Test内部,去掉SetUp和TearDown来增强测试的的表达性以及隔离性。

3.2 Xunit没有ExpectException

  不采用Attribute的方式来捕捉异常有两方面的好处:

  1. 在代码中直接断言(Assert)能捕捉到更多种类的异常。

  2. 遵守Arrange-Act-Assert(or "3A") 模式:即测试命名上“范围-作用-断言”规范。

public class TestClass1
{
[ Fact ]
public void testException()
{
Assert .Throws< InvalidOperationException >(() => operation());
}
void operation()
{
throw new InvalidOperationException ();
}
}

3.3 Xunit更像面向切面的语言

  Xunit中使用Fact、Theory、XxxData、Fact(Timeout=n)等标签来组织测试,从功能上讲更像切面编程。 请参考下一节。

3.4 Xunit去除了更多的Attribute

  保留很少一部分标签有利于简化测试框架,加快熟悉测试框架的时间,使框架更为简洁、实用。

NUnit 2.2 MSTest xUnit.net Comments
[Test] [TestMethod] [Fact] Marks a test method.
[TestFixture] [TestClass] n/a xUnit.net does not require an attribute for a test class; it looks for all test methods in all public (exported) classes in the assembly.
[ExpectedException] [ExpectedException] Assert.Throws orRecord.Exception xUnit.net has done away with the ExpectedException attribute in favor of Assert.Throws. SeeNote 1.
[SetUp] [TestInitialize] Constructor We believe that use of [SetUp]is generally bad. However, you can implement a parameterless constructor as a direct replacement. See Note 2.
[TearDown] [TestCleanup] IDisposable.Dispose We believe that use of[TearDown] is generally bad. However, you can implementIDisposable.Dispose as a direct replacement. See Note 2.
[TestFixtureSetUp] [ClassInitialize] IUseFixture<T> To get per-fixture setup, implement IUseFixture<T> on your test class. See Note 3
[TestFixtureTearDown] [ClassCleanup] IUseFixture<T> To get per-fixture teardown, implement IUseFixture<T> on your test class. See Note 3
[Ignore] [Ignore] [Fact(Skip="reason")] Set the Skip parameter on the[Fact] attribute to temporarily skip a test.
n/a [Timeout] [Fact(Timeout=n)] Set the Timeout parameter on the [Fact] attribute to cause a test to fail if it takes too long to run. Note that the timeout value for xUnit.net is in milliseconds.
[Property] [TestProperty] [Trait] Set arbitrary metadata on a test
n/a [DataSource] [Theory], [XxxData] Theory (data-driven test). SeeNote 4

3.4 Xunit使用IDisposable和IUseFixture<T>接口来代替显示声明SetUp和TestFixtureSetUp

  首先,创建一个支持IDisposable对象:

using System;
using System.Configuration;
using System.Data.SqlClient; public class DatabaseFixture : IDisposable
{
SqlConnection connection;
int fooUserID; public DatabaseFixture()
{
string connectionString = ConfigurationManager.ConnectionStrings["DatabaseFixture"].ConnectionString;
connection = new SqlConnection(connectionString);
connection.Open(); string sql = @"INSERT INTO Users VALUES ('foo', 'bar'); SELECT SCOPE_IDENTITY();"; using (SqlCommand cmd = new SqlCommand(sql, connection))
fooUserID = Convert.ToInt32(cmd.ExecuteScalar());
} public SqlConnection Connection
{
get { return connection; }
} public int FooUserID
{
get { return fooUserID; }
} public void Dispose()
{
string sql = @"DELETE FROM Users WHERE ID = @id;"; using (SqlCommand cmd = new SqlCommand(sql, connection))
{
cmd.Parameters.AddWithValue("@id", fooUserID);
cmd.ExecuteNonQuery();
} connection.Close();
}
}

  最后增加测试,并实现IClassFixture<DatabaseFixture>接口:

using System;
using System.Configuration;
using System.Data.SqlClient;
using Xunit; public class ClassFixtureTests : IClassFixture<DatabaseFixture>
{
DatabaseFixture database; public ClassFixtureTests(DatabaseFixture data)
{
database = data;
} [Fact]
public void ConnectionIsEstablished()
{
Assert.NotNull(database.Connection);
} [Fact]
public void FooUserWasInserted()
{
string sql = "SELECT COUNT(*) FROM Users WHERE ID = @id;"; using (SqlCommand cmd = new SqlCommand(sql, database.Connection))
{
cmd.Parameters.AddWithValue("@id", database.FooUserID); int rowCount = Convert.ToInt32(cmd.ExecuteScalar()); Assert.Equal(, rowCount);
}
}
}

  从这里读者可能体会到,Xunit更多的利用了C#本身的一些特性,而非使用一些特殊的Attribute或者方法(例如SetUp),在设计哲学上更多的考虑了对象自动实现自我管理的机制,而非人为去管理,从某种意义上来讲,解除了部分依赖性,将部分功能交给程序C#本身处理,减少工作量。

4. 文章引用

Martin Flower介绍Xunit: http://www.martinfowler.com/bliki/Xunit.html

Xunit Github地址:https://github.com/xunit/xunit

Nunit 官方地址:http://www.nunit.org/

周公介绍Xunit:http://zhoufoxcn.blog.51cto.com/792419/1172320/

舍弃Nunit拥抱Xunit的更多相关文章

  1. MSTest、NUnit、xUnit.net 属性和断言对照表

    MSTest.NUnit.xUnit.net 属性对照表 MSTest NUnit xUnit.net Comments [TestMethod] [Test] [Fact] Marks a test ...

  2. Nunit与Xunit介绍

    Nunit安装 首先说下,nunit2.X与3.X版本需要安装不同的vs扩展. nunit2.x安装 安装如上3个,辅助创建nunit测试项目与在vs中运行单元测试用例 . 1.Nunit2 Test ...

  3. Xunit和Nunit的区别

    https://www.cnblogs.com/Leo_wl/p/5727712.html 舍弃Nunit拥抱Xunit   前言 今天与同事在讨论.Net下测试框架的时候,说到NUnit等大多数测试 ...

  4. Xunit

    Attributes Note: This table was written back when xUnit.net 1.0 has shipped, and needs to be updated ...

  5. .NET Core系列 :4 测试

    2016.6.27 微软已经正式发布了.NET Core 1.0 RTM,但是工具链还是预览版,同样的大量的开源测试库也都是至少发布了Alpha测试版支持.NET Core, 这篇文章 The Sta ...

  6. 单元测试与Nunit的基本使用

    一.单元测试是什么 单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证.对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,C# ...

  7. [小北De编程手记] : Lesson 01 玩转 xUnit.Net 之 概述

    谈到单元测试,任何一个开发或是测试人员都不会觉得陌生.我想大多数的同学也都是接触过各种单元测试框架.关于单元测试的重要性,应该不会有太多的质疑.这个系列,我向大家介绍一下xUnit.Net的使用.就让 ...

  8. VS2013单元测试及代码覆盖率分析--Xunit

    1,Javaweb中有jmeter.jacoco.ant.badboy等集成测试代码覆盖率的方式,C#代码的覆盖率怎么测试呢?VS2013的IDE上本身并未集成测试的工具,以下讲解VS2013中C#代 ...

  9. [转载]单元测试之道(使用NUnit)

    首先来看下面几个场景你是否熟悉 1.你正在开发一个系统,你不断地编码-编译-调试-编码-编译-调试……终于,你负责的功能模块从上到下全部完成且编译通过!你长出一口气,怀着激动而又忐忑的心情点击界面上的 ...

随机推荐

  1. MVVM模式解析和在WPF中的实现(三)命令绑定

    MVVM模式解析和在WPF中的实现(三) 命令绑定 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在WPF中 ...

  2. 懒加载session 无法打开 no session or session was closed 解决办法(完美解决)

           首先说明一下,hibernate的延迟加载特性(lazy).所谓的延迟加载就是当真正需要查询数据时才执行数据加载操作.因为hibernate当中支持实体对象,外键会与实体对象关联起来.如 ...

  3. django server之间通过remote user 相互调用

    首先,场景是这样的:存在两个django web应用,并且两个应用存在一定的联系.某些情况下彼此需要获取对方的数据. 但是我们的应用肯经都会有对应的鉴权机制.不会让人家随随便便就访问的对吧.好比上车要 ...

  4. Dreamweaver 扩展开发:C-level extensibility and the JavaScript interpreter

    The C code in your library must interact with the Dreamweaver JavaScript interpreter at the followin ...

  5. netty5 HTTP协议栈浅析与实践

      一.说在前面的话 前段时间,工作上需要做一个针对视频质量的统计分析系统,各端(PC端.移动端和 WEB端)将视频质量数据放在一个 HTTP 请求中上报到服务器,服务器对数据进行解析.分拣后从不同的 ...

  6. 为.NET Core项目定义Item Template

    作为这个星球上最强大的IDE,Visual Studio不仅仅提供了很多原生的特性,更重要的是它是一个可定制的IDE,比如自定义Project Template和Item Template就是一个非常 ...

  7. 算法与数据结构(十七) 基数排序(Swift 3.0版)

    前面几篇博客我们已经陆陆续续的为大家介绍了7种排序方式,今天博客的主题依然与排序算法相关.今天这篇博客就来聊聊基数排序,基数排序算法是不稳定的排序算法,在排序数字较小的情况下,基数排序算法的效率还是比 ...

  8. UE4新手引导之下载和安装虚幻4游戏引擎

    1) 进入虚幻4的官方主页(https://www.unrealengine.com/) 这里你可以获得关于虚幻4的最新资讯,包括版本更新.博客更新.新闻和商城等.自2015年起,该引擎已经提供免费下 ...

  9. Consul 服务注册与服务发现

    上一篇:Mac OS.Ubuntu 安装及使用 Consul 1. 服务注册 对 Consul 进行服务注册之前,需要先部署一个服务站点,我们可以使用 ASP.NET Core 创建 Web 应用程序 ...

  10. 【Java学习系列】第3课--Java 高级教程

    本文地址 可以拜读: 从零开始学 Java 分享提纲: 1. Java数据结构 2. Java 集合框架 3. Java泛型 4. Java序列化 5. Java网络编程 6. Java发送Email ...