NCover:从覆盖范围中排除不执行的代码行

本文关键字:执行 代码 排除 覆盖 范围 NCover | 更新日期: 2023-09-27 18:34:18

以下代码中的 switch 语句具有编译器所需的 default 子句和一个很好的保护措施,但永远不会执行。在为其他所有内容编写测试之后,我无法(或应该(测试这一行。我不在乎我没有用测试覆盖这一行,但我的 TestDriven.net NCover 代码覆盖率报告确实显示了未经测试的行,这导致类覆盖率下降到 86%。有没有办法让NCover只排除这一行?

public static class OperandTypeExtensions
{
    public static string ToShortName(this OperandType type)
    {
        #region Contract
        Contract.Requires<InvalidEnumArgumentException>(Enum.IsDefined(typeof(OperandType), type));
        #endregion
        switch (type)
        {
            case OperandType.None: return "<none>";
            case OperandType.Int32: return "i32";
            case OperandType.Int64: return "i64";
            default:
                throw new NotSupportedException();
        }
    }
}

我的问题与这个问题类似,但在我的具体情况中没有一个答案有帮助。

NCover:从覆盖范围中排除不执行的代码行

您可以通过将整数值强制转换为 OperandType 来执行它,该值在 OperandType 枚举中不存在:

Assert.Throws<InvalidEnumArgumentException>(delegate { ((OperandType)Int32.MaxValue).ToShortName(); } );

顺便说一句,我认为 86% 的覆盖率没有什么不好

更新:在这里使用Contract没有任何好处。如果您的方法不支持值,您无论如何都会收到异常。

public static class OperandTypeExtensions
{
    public static string ToShortName(this OperandType type)
    {
        switch (type)
        {
            case OperandType.None: return "<none>";
            case OperandType.Int32: return "i32";
            case OperandType.Int64: return "i64";
            default:
                throw new NotSupportedException();
        }
    }
}

这里应该有default选项,因为如果要将新值添加到枚举OperandType,您的Contract将允许该值,但 switch 将不支持新选项。

UPDATE2:如果您确实需要此方法的 100% 覆盖率和合约,请使用 OperandType.None 作为默认选项:

public static class OperandTypeExtensions
{
    public static string ToShortName(this OperandType type)
    {
        Contract.Requires<InvalidEnumArgumentException>(Enum.IsDefined(typeof(OperandType), type));
        switch (type)
        {
            case OperandType.Int32: return "i32";
            case OperandType.Int64: return "i64";
            default:
                return "<none>";
        }
    }
}

并添加到有关枚举的测试断言中:

CollectionAssert.AreEquivalent(Enum.GetValues(typeof(OperandType)), 
                               new OperandType[] { OperandType.Int32,
                                                   OperandType.Int64, 
                                                   OperandType.None });

我还想让所有源文件达到 100%,不是 %,而是为了避免每次运行代码覆盖率工具时都仔细检查每个类是否存在误报。

在这种情况下和IMO,如果函数是公开的,这意味着你应该用类似的东西来测试它

Assert.Throws<NotSupportedException>( OperandTypeExtensions.ToShortName() );

其他可能发生的情况

通常,当throwsDebug.Assert为私有的函数时,会出现更大的问题。在这种情况下,有时测试无法到达这些线。或者不能封装在Assert.Throws中。

我发现确保每一行都得到执行的唯一方法。远非理想且非常丑陋,我宁愿这样的注释注释来禁用它。虽然在 C# 中不起作用。

private string ToShortName(this OperandType type)
{
    var result = "";
    switch (type)
    {
        case OperandType.Int32: result = "i32";
        case OperandType.Int64: result = "i64";
    }
    Debug.Assert(result != "", "Invalid type.");
    return result;
}

使用此解决方案,在源代码中,它将在返回空字符串(在调试中(之前中断,并且代码覆盖率将看到 Debug.Assert 行已执行。

附言虽然,我想知道是否有更好的解决方案,例如注释或专门禁用代码块的东西。