簡體   English   中英

NUnit:在單個測試中運行多個斷言

[英]NUnit: Running multiple assertions in a single test

我被要求編寫一個測試應用程序,它需要在數據庫的多行上測試一個新的存儲過程,本質上我想做這樣的事情:

[Test]
public void TestSelect()
{
    foreach(id in ids)
    {
        DataTable old = Database.call("old_stored_proc",id);
        DataTable new_ = Database.call("new_stored_proc",id);

        Assert.AreEqual(old.Rows[0]["column"],ne_.Rows[0]["column"]);
    }
}

當我運行此測試時,如果 1 行與另一行不匹配,則整個測試失敗; 相反,我想計算斷言通過了多少次以及失敗了多少次。 有沒有辦法用 NUnit 做到這一點?

我意識到 NUnit 可能有點矯枉過正,如果沒有它,這是一項簡單的任務......我只是想學習它。 ;)

好像你只是在斷言錯誤的事情。 如果要檢查所有值,然后斷言沒有錯誤(或顯示錯誤數),請嘗試以下操作:

[Test]
public void TestSelect()
{
    int errors = 0;
    foreach(id in ids)
    {
        DataTable old = Database.call("old_stored_proc",id);
        DataTable new_ = Database.call("new_stored_proc",id);

        if (old.Rows[0]["column"] != new_.Rows[0]["column"])
        {
            errors++;
        }            
    }

    Assert.AreEqual(0, errors, "There were " + errors + " errors.");
}

1) 如果 id 是常量並且在測試運行時沒有查找,則為每個 id 創建一個單獨的單元測試裝置。 這樣你就會知道哪些 id 實際上失敗了。 有關數據驅動測試的問題,請參見此處:
http://googletesting.blogspot.com/2008/09/tott-data-driven-traps.html

2) 如果您需要動態查找 id 從而無法為每個 id 創建一個裝置,請使用 akmad 的建議並進行一次更改。 保留值不相等的 id 列表並將該列表添加到錯誤消息中。 診斷僅說明錯誤數量的失敗測試將非常困難,因為您不知道導致錯誤的 ID 是什么。

3) 我不知道在 NUnit 中做起來會有多困難,但是在 PyUnit 中,當我們需要對動態生成的數據運行測試時,我們會動態創建測試裝置並將它們附加到 TestCase 類中,這樣我們就有了一個失敗的對每條未通過的數據進行測試。 雖然我想如果沒有 python 的動態能力,這會困難得多。

我知道這個問題是關於 NUnit 的,但有趣的是, Gallio/MbUnit有一個特性,它允許一次運行和捕獲多個斷言。

[Test]
public void MultipleTest()
{
    Assert.Multiple(() =>
    {
       Assert.IsTrue(blabla);
       Assert.AreEqual(pik, pok);
       // etc.
    }
}

Assert.Multiple正在捕獲所有失敗的斷言,並將在測試結束時報告它們。

我會計算不匹配的行數,然后編寫一個斷言,將這個數字與 0 進行比較,並返回消息中不匹配字符串的數量。

您也可以Assert.Greater使用Assert.Greater

PS 原則上,您應該嘗試為每個單元測試做一個斷言。 這就是它的要點。

那么你可以聲明一個計數器,然后斷言計數器的值來確定通過/失敗

此外,您可以在測試設置中完成大部分工作,然后只需創建多個測試。

我不清楚為什么在同一個測試中需要所有斷言 stmts。

基於奠定了你的目標,如果一個行不匹配另一個整個測試應該失敗。 計算斷言通過或失敗的次數比將預期的結果與實際得到的結果進行比較所提供的信息要少。

我最近有同樣的問題。 我將計數錯誤的想法與 Yann Trevin 提到的 Assert.Multiple 結合到 IEnumberable 的擴展方法中,讓我可以執行以下操作:

[Test]
public void TestEvenNumbers()
{
    int[] numbers = new int[] { 2, 4, 12, 22, 13, 42 };
    numbers.AssertAll((num) => Assert.That((num % 2) == 0, "{0} is an odd number", num));
}

這導致 NUnit 輸出:

TestEvenNumbers:
  5 of 6 tests passed; 0 inconclusive
FAILED: 13:   13 is an odd number
  Expected: True
  But was:  False

  Expected: 6
  But was:  5

OP問題的解決方案是:

[Test]
public void TestSelect()
{
    ids.AssertAll(CheckStoredProcedures);
}

private void CheckStoredProcedures(Id id)
{
    DataTable old = Database.call("old_stored_proc",id);
    DataTable new_ = Database.call("new_stored_proc",id);

    Assert.AreEqual(old.Rows[0]["column"], new_.Rows[0]["column"]);
}

這是擴展方法(請注意,為了與 Linq 術語保持一致,我使用了“All”而不是“Multiple”):

using System;
using System.Text;
using System.Collections.Generic;
using NUnit.Framework;

public static class NUnitExtensions
{
    public static void AssertAll<T>(this IEnumerable<T> objects, Action<T> test)
    {
        int total = 0;
        int passed = 0;
        int failed = 0;
        int inconclusive = 0;
        var sb = new StringBuilder();
        foreach (var obj in objects)
        {
            total++;
            try
            {
                test(obj);
                passed++;
            }
            catch (InconclusiveException assertion)
            {
                inconclusive++;
                string message = string.Format("INCONCLUSIVE: {0}: {1}", obj.ToString(), assertion.Message);
                Console.WriteLine(message);
                sb.AppendLine(message);
            }
            catch (AssertionException assertion)
            {
                failed++;
                string message = string.Format("FAILED: {0}: {1}", obj.ToString(), assertion.Message);
                Console.WriteLine(message);
                sb.AppendLine(message);
            }
        }

        if (passed != total)
        {
            string details = sb.ToString();
            string message = string.Format("{0} of {1} tests passed; {2} inconclusive\n{3}", passed, total, inconclusive, details);
            if (failed == 0)
            {
                Assert.Inconclusive(message);
            }
            else
            {
                Assert.AreEqual(total, passed, message);
            }
        }
    }
}

如果是簡單的硬編碼 ID 列表,則可以使用[TestCase()]屬性

[Test]
[TestCase(1234)]
[TestCase(5678)]
[TestCase(7654)]
public void TestSelect(int id)
{
    DataTable old = Database.call("old_stored_proc", id);
    DataTable new_ = Database.call("new_stored_proc", id);

    Assert.AreEqual(old.Rows[0]["column"], new_.Rows[0]["column"]);
}

這將為每個 ID 生成三個單獨的測試,您使用的任何 nunit 測試運行器都將顯示通過/失敗計數。

如果需要生成動態 ID 列表,則建議使用[TestCaseSource()]屬性

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM