国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

舍棄Nunit擁抱Xunit

2019-11-17 02:22:21
字體:
來源:轉載
供稿:網友

舍棄Nunit擁抱Xunit

前言

  今天與同事在討論.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.2MSTestxUnit.netComments
[Test][TestMethod][Fact]Marks a test method.
[TestFixture][TestClass]n/axUnit.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.ThrowsorRecord.ExceptionxUnit.net has done away with the ExpectedException attribute in favor ofAssert.Throws. SeeNote 1.
[SetUp][TestInitialize]ConstructorWe believe that use of[SetUp]is generally bad. However, you can implement a parameterless constructor as a direct replacement. SeeNote 2.
[TearDown][TestCleanup]IDisposable.DisposeWe believe that use of[TearDown]is generally bad. However, you can implementIDisposable.Disposeas a direct replacement. SeeNote 2.
[TestFixtureSetUp][ClassInitialize]IUseFixture<T>To get per-fixture setup, implementIUseFixture<T>on your test class. SeeNote 3
[TestFixtureTearDown][ClassCleanup]IUseFixture<T>To get per-fixture teardown, implementIUseFixture<T>on your test class. SeeNote 3
[Ignore][Ignore][Fact(SkSet 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(1, 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/


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 喀喇| 封开县| 沂源县| 江陵县| 弋阳县| 嘉义市| 社旗县| 和龙市| 临汾市| 得荣县| 红安县| 孟村| 赤水市| 阜新| 前郭尔| 庄河市| 青州市| 禄丰县| 泾源县| 富裕县| 读书| 孝昌县| 兴宁市| 商水县| 秦安县| 兰考县| 山东省| 连平县| 泸溪县| 那坡县| 东莞市| 新龙县| 望城县| 普兰店市| 静宁县| 顺义区| 锡林浩特市| 广丰县| 洪洞县| 收藏| 宁陕县|