C# 我是否应该测试这些方法不';t抛出异常?

C# 我是否应该测试这些方法不';t抛出异常?,c#,unit-testing,nunit,C#,Unit Testing,Nunit,我正在通过单元测试完成我的第一个婴儿步骤,并编写了(除其他外)以下两种方法: [TestCase] public void InsertionSortedSet_AddValues_NoException() { var test = new InsertionSortedSet<int>(); test.Add(5); test.Add(2); test.Add(7); tes

我正在通过单元测试完成我的第一个婴儿步骤,并编写了(除其他外)以下两种方法:

    [TestCase]
    public void InsertionSortedSet_AddValues_NoException()
    {
        var test = new InsertionSortedSet<int>();

        test.Add(5);
        test.Add(2);
        test.Add(7);
        test.Add(4);
        test.Add(9);
    }

    [TestCase]
    public void InsertionSortedSet_AddValues_CorrectCount()
    {
        var test = new InsertionSortedSet<int>();

        test.Add(5);
        test.Add(2);
        test.Add(7);
        test.Add(4);
        test.Add(9);

        Assert.IsTrue(test.Count == 5);
    }
[TestCase]
public void InsertionSortedSet_AddValues_NoException()
{
var test=new InsertionSortedSet();
试验。添加(5);
测试。添加(2);
试验。添加(7);
试验。添加(4);
试验。添加(9);
}
[测试用例]
公共void InsertionSortedSet\u AddValues\u CorrectCount()
{
var test=new InsertionSortedSet();
试验。添加(5);
测试。添加(2);
试验。添加(7);
试验。添加(4);
试验。添加(9);
Assert.IsTrue(test.Count==5);
}
是否真的需要
NoException
方法?如果要抛出异常,它也将在
CorrectCount
方法中抛出


我倾向于将它作为两个测试用例(可能将重复的代码重构为另一种方法),因为一个测试应该只测试一件事,但可能我的解释是错误的。

我总是测试工作和非工作用例。通过这种方式,您可以验证代码是否工作,返回正确的结果,并以预期的方式处理错误。

Imo,如果您确信
InsertionSortedSet
列表工作正常(我不确定它来自何处),我将跳过测试
InsertionSortedSet\u AddValues\u NoException
,正如您所想的那样,如果有必要的话


当然,最好尽可能多地进行测试。

让一个方法测试被测试的方法在您期望的时候抛出异常,这样做更有意义。您进行的第一次测试没有第二次测试尚未涵盖的行为。

这里没有100%正确答案

一方面,你是对的,一次测试应该测试一件事。
如果其中一个测试将来可能会更改,那么您将无法确定是否正在检查另一个测试是否通过,这一点尤其正确

另一方面,您正在创建冗余,因为两个测试实际上都在检查相同的内容。

这种冗余只有在测试花费太多时间运行的情况下才是不好的,但由于(看起来)您只有几个测试,这应该不是问题。

第一个测试中没有断言,也没有预期的异常,我认为应该重构它


IMO,一个测试应该检查不正确的行为(期望抛出错误),另一个测试应该检查正确的行为(没有异常,返回了正确的值)。

用最简单的话来说,IMO测试方法不能做的事情可能非常棘手,当你思考的时候,你可以想出越来越多的场景。反过来说,断言您的代码做了您希望它做的事情是单元测试的主要目的


有两个简单的问题通常可以帮助我发现可疑的测试,并判断测试是否有意义:

  • 测试练习所需功能的哪一部分
  • 我可以在测试类中做什么简单的改变来打破测试
请注意,考虑到第二次测试(
\u CorrectCount
),处理这些问题非常容易。我们还没有真正看到
Add
method代码,但我们很有可能会产生一个不错的猜测,即什么可以被更改以打破测试。经过测试的功能更加明显。答案是直观的,而且看起来很快(这很好!)

现在让我们试着回答第一次测试的问题(
\u NoException
)。它立即提出了新的问题(工作代码是一种实际的功能吗?不是很明显吗?这不是隐含的吗?这不是我们一直努力的目标吗?为什么最后没有断言?我如何才能让它失败?)。对于第二个问题,更糟糕的是,破坏该测试可能需要显式地抛出异常。。。我们都同意,这不是我们要走的路

结论
这很简单。第二个测试是编写良好的单元测试的完美例子。它很短,只测试一件事,很容易理解。第一次测试不是。尽管它同样简短(看起来很简单),但它引入了新的问题(虽然它确实应该回答已经陈述过的问题-是的,
添加了吗
实际添加了吗?是的。),因此带来了不必要的复杂性。

因此,在您看来,不值得包括一个检查无异常运行的测试,什么时候作为另一个测试的一部分运行?@Kaster:没错。第二个测试用例已经检查“无异常”。而且可能做得更好。我认为值得测试的是,在极少数情况下没有例外,只有在回归测试中。例如,当被测试的部分在某些条件下不能一起工作时,就像Henk(和OP)所说的:如果抛出任何异常,第二个测试将失败-为什么只需删除断言就可以复制代码?它在很大程度上违反了DRY…我理解你的意思,我分别检查无效参数等,但我不确定你的答案是否适用于这种情况,因为在第一个方法中,我没有检查结果,我检查方法是否运行正常。这是我正在讨论删除的支票。这取决于你的测试目标。当我做TDD时,我会测试“预期”和“意外”行为。我会修改您的第一个测试,使其断言显示数据按预期插入-否则,为什么会出现?我认为您至少需要在_NoException测试结束时
Assert.IsTrue(true)
。然后你可以更好地看到它是不需要的。我宁愿测试一个方法是否会抛出一个异常,如果这是对一些输入的预期。我认为Dijkstra说得最好:“程序测试可以用来显示错误的存在,但永远不会显示它们的缺失!”这是对