6

我被要求编写一个测试应用程序,需要在数据库中的多行上测试一个新的存储过程,本质上我想做这样的事情:

[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 可能是矫枉过正,没有它这是一项简单的任务......我只是想学习它。;)

4

8 回答 8

9

好像你只是在断言错误的事情。如果您想检查所有值,然后断言没有错误(或显示错误数),请尝试以下操作:

[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.");
}
于 2008-10-03T16:07:19.403 回答
5

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 的动态能力,这会更加困难。

于 2008-10-03T16:21:56.130 回答
4

我知道这个问题是专门针对 NUnit 的,但有趣的是,Gallio/MbUnit有一个特性,它允许同时运行和捕获多个断言。

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

Assert.Multiple正在捕获所有失败的断言,并将在测试结束时报告它们。

于 2010-05-28T06:22:03.517 回答
1

我将计算不匹配的行数,然后编写一个断言,将这个数字与 0 进行比较,并返回消息中不匹配字符串的数量。

你也可以用Assert.Greater这个。

PS原则上,您应该尝试为每个单元测试做一个断言。这就是它的要点。

于 2008-10-03T16:03:54.107 回答
0

好吧,您可以声明一个计数器,然后断言计数器的值以确定通过/失败

此外,您可以在测试设置中完成大部分工作,然后创建多个测试。

我不清楚为什么您需要在同一个测试中使用所有断言 stmts。

于 2008-10-03T16:01:12.910 回答
0

根据您制定的目标,如果一行与另一行不匹配,整个测试应该会失败。计算一个断言通过或失败的次数比将预期结果与实际得到的结果进行比较所提供的信息更少。

于 2008-10-09T13:43:53.357 回答
0

我最近有同样的问题。我将计数错误的想法与 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);
            }
        }
    }
}
于 2014-05-09T17:48:39.607 回答
0

如果是简单的硬编码 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()]属性

于 2018-06-20T15:15:08.317 回答