27

我想知道有人应该如何使用 Assert.Inconclusive()。

如果我的单元测试由于测试目的以外的原因而即将失败,我会使用它。

例如,我在一个类上有一个计算整数数组总和的方法。在同一个类上,还有一种计算元素平均值的方法。它是通过调用 sum 并将其除以数组的长度来实现的。

为 Sum() 编写单元测试很简单。但是,当我为 Average() 编写测试时,Sum() 失败了,那么 Average() 也可能会失败。

Average 的失败并没有明确说明失败的原因;它失败的原因不是它应该测试的原因。这就是为什么我会检查 Sum() 是否返回正确的结果,否则我会 Assert.Inconclusive()。

这被认为是好的做法吗?Assert.Inconclusive 的用途是什么?还是我应该通过隔离框架来解决前面的例子?

4

4 回答 4

26

不确定的测试是您无法确定结果的测试。例如,如果您有一个使用某种外部资源(例如 Internet 连接)的测试怎么办。如果连接当前不可用,这并不意味着测试失败。另一方面,你不应该只是将它标记为成功而不实际运行它。因此,您将其标记为不确定,这可以在测试报告中看到。

注意:通常,您不应在测试中使用此类外部资源,因为这会使测试变得脆弱。

对于尚未完成的测试,我使用 MbUnit 的Explicit属性。

于 2009-08-02T18:10:23.997 回答
16

当我使用 VS 生成单元测试时,我得到了 Assert.Inclusive 用于生成的测试方法,并且通常我在工作时更改了断言等等。我使用测试结果中 Assert.Inconclusive 的问号作为标记来快速告诉我哪些测试我还没有完成。

嗯,这就是我使用它的方式。从它的名字“不确定”来看,我猜你可以用它来表示你的不确定状态,只要你记录它的含义。

但是,从您的Average()方法的描述来看,我认为您的单元测试可能不够原子,无法仅涵盖一个“单元”,一个特定场景。有时,我会为一个方法编写 2 或 3 个单元测试方法。或者您可以将您的Average()方法分解为涵盖单一职责的较小方法。这样,您可以在对您进行单元测试之前对这些较小的方法进行单元测试Average()


约翰内斯,

这就是我将如何实现Sum()andAverage()方法。

public static class MyMath
{
    private static void ValidateInput(ICollection<int> numbers)
    {
        if (numbers == null)
            throw new ArgumentNullException("numbers", "Null input.  Nothing to compute!");
        if (numbers.Count == 0)
            throw new ArgumentException("Input is empty.  Nothing to compute!");
    }

    public static int Sum(int[] numbers)
    {
        ValidateInput(numbers);

        var total = 0;
        foreach (var number in numbers)
            total += number;

        return total;
    }

    public static double Average(int[] numbers)
    {
        ValidateInput(numbers);
        return Sum(numbers) / numbers.Length;
    }
}

为简单起见,我只是ArgumentExceptionValidateInput(ICollection<int>)方法中抛出异常。您还可以检查溢出和抛出方法的OverflowException可能性ValidateInput(ICollection<int>)

话虽如此,这就是我将如何测试该Average(int[])功能。

[TestMethod]
public void AverageTest_GoodInput()
{
    int[] numbers = {1, 2, 3};
    const double expected = 2.0;
    var actual = MyMath.Average(numbers);
    Assert.AreEqual(expected, actual);
}

[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void AverageTest_NullInput()
{
    int[] numbers = null;
    MyMath.Average(numbers);
}

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void AverageTest_EmptyInput()
{
    var numbers = new int[0];
    MyMath.Average(numbers);
}

通过这些测试设置,我可以确定当所有测试都通过时,我的功能是正确的。好吧,除了溢出的情况。现在我可以回到ValidateInput(ICollection<int>)方法来添加逻辑来检查溢出,然后再添加一个测试以期望OverflowException抛出导致溢出的输入类型。或者,如果您喜欢使用 TDD,请按相反的顺序进行操作。

我希望这有助于澄清这个想法。

于 2009-08-02T18:50:24.430 回答
10

我只对尚未编写的单元测试进行 Assert.Inconclusive 。有时在写东西时,我会意识到一些我不想错过的极端情况。于是我赶紧跳过去,用描述性的名字编写测试方法,并添加一行 Assert.Inconclusive。

这样做的原因是它提供了我需要测试的东西的文档,而不会过多地中断我的工作流程。它还可以在结果列表中快速过滤掉测试失败。有一个不确定的失败意味着我没有破坏任何东西,我只是写了更多的测试。

于 2009-08-02T17:06:35.693 回答
8

Assert.Inconclusive 表示:

我还没有写测试;我只创建了测试方法

-或者-

我的测试有一个依赖项,并且该依赖项不可用。例如

List<Customer> custs = o.GetAllCustomers();
if (custs.Count == 0)
{
  Assert.Inconclusive("No customers to test");
  return;
}
于 2010-05-04T19:45:02.003 回答