内部安全检查,如何达到100%的代码覆盖率?

问题描述 投票:0回答:1

我有很多类似于以下的类:

public class Foo
{
    private readonly Ba _ba;

    private Foo(Ba ba)
    {
        if (ba is null) throw new ArgumentNullException(ba);

        _ba = ba;
    }
}

在其他类的内部,我称之为Foo的构造函数,但由于这是无意的,在每个构造函数中调用ba不是null

我为组合框架编写了很多测试方法,但我无法达到100%的代码覆盖率,因为上面的代码片段中的异常是更新的抛出。

我看到以下替代方案:

  • 删除空检查:这将适用于当前项目实现,但每当我可能添加意外调用Foo(null)时,调试将更加困难。
  • 使用[ExcludeFromCodeCoverage]装饰构造函数:这适用于当前的Foo(Ba)实现,但每当我可能更改实现时,构造函数中的新代码路径可能会开发并意外地错过测试。

你会如何解决困境?


Notes

代码示例是用C#编写的,但问题可能解决了一般的单元测试/异常处理问题。

C#8可能会通过introducing non-nullable reference types解决这个问题,但我一直在寻找一个好的解决方案,直到它稳定发布。

c# unit-testing testing exception code-coverage
1个回答
2
投票

您错过了最重要的替代方案:不要将其视为实现100%代码覆盖率的理想目标。

严格来说,代码中的健壮性检查无法以合理的方式进行测试。这也会发生在代码的其他各个部分 - 它经常发生在switch语句中,其中明确涵盖了所有可能的情况,并且添加了一个额外的默认情况,只是为了抛出异常或以其他方式处理这种“不可能”的情况。或者,考虑添加到代码中的断言语句:由于断言永远不会失败,因此严格来说,您将永远无法覆盖隐藏在断言语句中的else分支 - 如何测试断言中的表达式对于实际上检测出你想要它的问题?

删除这样的健壮性代码和断言并不是一个好主意,因为它们还可以保护您免受未来更改的不良副作用。从您所显示的示例中删除覆盖率分析中的代码可能是可以接受的,但在我提到的大多数情况下,这不是一个好的选择。最后,您必须做出明智的决定(通过详细查看覆盖率报告,而不仅仅是整体百分比),您的代码的哪些陈述/分支等确实需要涵盖哪些,哪些不需要。

并且,作为最后一点,请注意高代码覆盖率并不一定表明您的测试套件具有高质量。如果测试套件能够检测到可能存在的代码中的错误,那么它的质量很高。您可以拥有100%覆盖率的测试套件,但不会检测到任何潜在的错误。

© www.soinside.com 2019 - 2024. All rights reserved.