.net持續集成測試篇之Nunit參數化測試

系列目錄html

在進行單元測試的時候,不少時候,不少時候咱們都是在單元測試方法內部提供特定的值,可是這樣測試每每形成樣本數不足從而致使覆蓋的結果不夠全面,不少時候咱們更想提供來自外部的,知足條件的一組值來進行測試.其實Nunit框架自己提供了爲測試用例提供值的能力.咱們能夠對它進行擴展來實現導入外部的值來填充到測試方法內部.不少朋友也本身寫了很多按照必定規則生成值的方法.可是每每都是在方法內部直接調用,這樣就會和單元測試的邏輯混雜在一塊,致使測試方法自己不夠簡潔.其實能夠根本測試框架自己的能力改形成爲註解的方式,這樣參數生成邏輯和測試邏輯一目瞭然.後面咱們還會講解基於Autofixture框架來生成填充數據,autofixture相比咱們本身寫的值填充方法,每每功能更增強大.後面咱們將見證其強大之處.框架

提供普通參數

很容易發現,單元測試的方法都是不帶參數的,有些時候咱們須要爲一個要測試的方法(並不是單元測試方法)提供多個參數進行測試,這就會致使一個問題:咱們須要寫不少相似的測試方法,只是參數不同,這樣維護起來不方便,同時大量重複的工做也很煩.下面介紹Nunit裏如何爲測試提供參數dom

int  Add(int x, int y)
        {
            return x + y;
        }

以上是咱們要測試的方法.ide

雖然Nunit測試方法正常狀況下是不支持參數的,可是若是對參數添加的values註解,Nunit便會把這些參數應用到測試.
咱們看一下編寫的測試方法單元測試

[Test]
        public void DemoTest([Values(3,4,5)]int a,[Values(6,7,8)]int b)
        {
            var result = Add(a, b);
            Assert.AreEqual(a + b, result);
        }

咱們運行以上方法,能夠看到測試結果經過,可是咱們看一下測試面板(Test Explorer)測試

avatar
經過截圖咱們很容易發現,這個測試方法一共運行的九次!再仔細看看方法對應的參數,能夠看到它是使用組合的方式把全部的可能都組合一遍.code

可是有些時候咱們想要的不是這樣的組合,咱們想要的更多時候是(3,6),(4,7),(5,8)這樣的組合,如何作到呢,仍然看一段示例代碼htm

[Test]
        [Sequential]
        public void DemoTest([Values(3,4,5)]int a,[Values(6,7,8)]int b)
        {
            var result = Add(a, b);
            Assert.AreEqual(a + b, result);
        }

咱們看看運行結果blog

avatar

此次只運行了三次,而且參數的組合正如咱們期待的.
這個方法和上面的同樣,只是多了一個[Sequential]註解字符串

注意Values註解裏的參數都是Object類型,運行時候轉換爲參數的真正類型,若是沒法轉換則會拋出異常.好比[Values("a")]int x因爲a是字符串類型,經過內置方法沒法轉換爲int,因些會拋出異常.

提供基於範圍的參數

上面的測試Values(3,4,5)和Values(6,7,8)都是連續的數字,若是鏈接的參數更多,咱們可使用基於範圍的參數.

看如下示例代碼

[Test]
        [Sequential]
        public void DemoTest([Range(3,5)]int a,[Range(6,8)]int b)
        {
            var result = Add(a, b);
            Assert.AreEqual(a + b, result);
        }

咱們把Values註解改成Range註解,就ok了

提供隨機參數

咱們還能夠爲測試提供一些隨機數,以使測試變得更隨機,覆蓋範圍更大

這裏要使用Random註解
請看下面示例

[Test]
       [Sequential]
        public void DemoTest([Random(3)]int a, [Random(3)]int b)
        {
            var result = Add(a, b);
            Assert.AreEqual(a + b, result);
        }

Random的參數爲要生成隨機數的個數.

Random還有一重載以支持生成隨機數的最大值和最小值

[Test]
       [Sequential]
        public void DemoTest([Random(3,10,2)]int a, [Random(5,9,3)]int b)
        {
            var result = Add(a, b);
            Assert.AreEqual(a + b, result);
        }

示例中Random的三個參數分別是最小值,最大值和個數

[info]Random的最大值和最小值不只能夠是整數,也能夠是小數

提供計算參數

先看一個示例

[Test]
       [Sequential]
        public void DemoTest(DateTime dt1)
       {
           DateTime dt2 = default(DateTime);
           Assert.Greater(dt1, dt2);
       }

這裏測試方法的參數是Datetime類型,咱們如何給給它提供值呢,不少人可能會想使用Values[DateTime.Now] 來註解dt1參數,然而不幸的是Values註解只接受const類型的值,這裏介紹ValueSource註解來解決這個問題.

ValueSource的機制是使用一個方法來獲取值,而後提供給測試方法參數,它接受一個字符串類型的參數,用於指定提供值的方法名.

咱們用如下方法生成一些DateTime值

static IEnumerable<DateTime> GetPeople()
        {
            yield return DateTime.Now;
            yield return DateTime.Now.AddDays(2);
        }

以上方法生成了一個包含兩個DateTime值的集合.下面咱們看如何使用它

[Test]
        public void DemoTest([ValueSource(nameof(FirstUnitTest.GetPeople))]DateTime dt1)
       {
           DateTime dt2 = default(DateTime);
           Assert.Greater(dt1, dt2);
       }

咱們使用nameof獲取剛纔生成的用於提供值的方法,做爲ValueSource的參數.

使用nameof而不是使用手寫字符串的好處在於nameof能夠有智能提示,防止手寫出現錯誤,另外就是若是方法名更改,這裏將會拋出了一個錯誤,靜態字符串不會提示錯誤,若是在運行時找不到這個方法則會拋出運行時錯誤

用於爲ValueSource提供值的方法必須是靜態的

以上代碼,咱們把提供值的方法直接寫在測試類裏,這並非一種很好的實踐,一種好的作法是把全部的用於提供值的方法放在一個外部的類中.

咱們把這個類移動到一個叫做MyValueProvider的類中
代碼以下

public class MyValueProvider
    {
        public static IEnumerable<DateTime> GetPeople()
        {
            yield return DateTime.Now;
            yield return DateTime.Now.AddDays(2);
        }
    }

單元測試方法改爲以下:

[Test]
        public void DemoTest([ValueSource(typeof(MyValueProvider),nameof(MyValueProvider.GetPeople))]DateTime dt1)
       {
           DateTime dt2 = default(DateTime);
           Assert.Greater(dt1, dt2);
       }

若是把值提供方法不在本類中(當前測試方法所在的類),提供一個Type類型(提供值的方法所在的類的類型)做爲第一個參數,方法名做爲第二個參數.

上面講的都是基於參數註解的值提供方法,這裏基於方法的註解的值提供方法.固然,它完成的功能基於參數註解的方法也一樣能完成.

TestCaseAttribute註解

看如下代碼片斷

[TestCase(3,4)]
        public void DemoTest(int x,int y)
       {
           var val = Add(x, y);
           Assert.AreEqual(x + y, val);
       }

其中用到的Add方法代碼以下

int  Add(int x, int y)
        {
            return x + y;
        }

TestCase的工做原理是這樣的,它提供的值是基於位置的,每個位置處的值賦值給第一個參數,第二個位置處的值提供給第二個參數...

有了TestCase註解以後,Test註解再也不是必要的.

TestCaseSourceAttribute註解

從上ValueSource咱們很容易想到可能會有TestCaseSource,實際上也確實是這樣的,TestCaseSource功能也同ValueSource同樣,用於提供基於計算的結果.

用於提供值的類以下

public class MyValueProvider
   {
       public static ArrayList ar = new ArrayList
       {
           new int[] {3, 4},
           new int[] {5, 9},
           new int[] {9, 22}
       };
   }

測試方法以下

[TestCaseSource(typeof(MyValueProvider),nameof(MyValueProvider.ar))]     
        public void DemoTest(int x,int y)
       {
           var val = Add(x, y);
           Assert.AreEqual(x + y, val);
       }

從這個例子咱們可看到,不只方法能夠提供值,屬性,普通字段也能夠提供值

爲TestCaseSource提供值的字段,方法,屬性也必須是靜態的

TestCase和TestCaseSource都支持多重註解,有幾個註解,測試方法就會運行幾回.

相關文章
相關標籤/搜索