单元测试:Linq的延迟断言


18

可以添加这样的延迟断言吗

var actualKittens = actualKittens.Select(kitten => {
    Assert.IsСute(kitten);
    return kitten
});

为什么?因此,即使使用期望实现实例化的语句,我也可以仅迭代一次:

CollectionAssert.AreEquivalent(expectedKittens, actualKittens.ToList());

而且它可能不仅是Select,而且是定义了迭代器且具有大量检查和逻辑(例如,一些计数和过滤)的方法。

令人怀疑的种子是在测试失败的情况下读取和调试此类代码的复杂性。


1
我不会依靠它来进行测试,但是如果没有更好的解决方案,有时可以在生产代码中做到这一点。您可以使自己成为一个辅助函数sequence.WithSideEffect(item => Assert.IsCute(item)),使其变得更干净。
usr

@usr似乎您已捕获到这种方式的主要缺陷-迭代器的副作用。
SerG

您是否还不必重复两次,一次生成列表,然后再次将其与进行比较expectedKittens?您只是隐藏了方法调用背后的迭代。
IllusiveBrian

@IllusiveBrian在这个例子中,是的。它仍然比带有额外的要少.All()
SerG

Answers:


37

是否可以添加这样的延迟断言[..]

,不是。为什么?因为如果出于任何原因删除了第二个断言,测试仍将变为绿色,并且您会认为它仍然可以工作,但是由于集合不会被枚举,因此它无效。如果您有两个或多个独立的断言,即使您禁用其中一个,它们也将继续工作。

考虑以下组合:

Assert.IsTrue(actualKittens.All(x => x.IsCute());
CollectionAssert.AreEquivalent(expectedKittens, actualKittens.ToList());

现在,即使您禁用或删除其中一个断言,另一个也将继续执行其工作。另外,如果您忘记实现该集合,则可能需要花费更长的时间才能运行它,但是它仍然可以正常工作。独立测试更加强大和可靠。

还有第二个没有。我不确定其他框架如何处理它,但是如果您使用的是MS Test平台,则不会知道哪个测试失败。如果您双击失败的测试,它将显示CollectionAssert为失败,但实际上是嵌套Assert错误,因此很难调试。这是一个例子:

    [TestMethod]
    public void TestMethod()
    {
        var numbers = new[] { 1, 2, 3 }.Select(x =>
        {
            Assert.Fail("Wrong number.");
            return x;
        });

        // This will fail and you won't be sure why.
        CollectionAssert.AreEqual(new[] { 1, 2, 3 }, numbers.ToList()); 

    }

这意味着第一次测试实际上是没有用的,因为它无助于发现错误。您不知道是否由于数字无效或两个集合不同而失败。


为什么?因此,即使语句期望实现集合,我也只能迭代一次

我不知道你为什么关心它?这些是单元测试。您不必对它们的每一部分进行优化,通常测试不需要数百万个项目,因此性能不是问题。

您将需要维护这样的测试,那么为什么要使它们变得比所需的更为复杂?写简单断言该工作。


如果出于某种原因确实需要在控制流中掩埋一个断言,那么一种确保执行该断言的方法是在嵌套断言之前保持递增/设置为true的计数器/标志。稍后,我们可以通过检查此计数器来断言预期的控制流已采取。并不完美,但主要针对您的第一个批评。
阿蒙

1
此外,您或其他人将在6个月的时间内返回延迟的断言,并且不得不浪费时间来弄清它。
DavidTheWin'7

您的示例有问题。调用ToList会迭代可枚举的对象,不是吗?
RubberDuck

1
@RubberDuck是的,它将并且也将失败,但是不会在,Assert.Fail而是在CollectionAssert,您将无法说出哪个断言实际上出了问题。我的意思是VS不会专注于Assert.Fail其他方面,现在您可以进行调试了。
t3chb0t
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.