【问题标题】:Why is this string property shown to be fully covered when it's not supposed to be?为什么这个字符串属性不应该被完全覆盖?
【发布时间】:2011-12-18 13:47:33
【问题描述】:
class Program
{
    static void Main(string[] args)
    {
        var x = new Program();
        Console.Write(x.Text);
        Console.Write(x.Num);
        //Console.Write(x.Num);//line A
    }

    private string Text_;
    public string Text
    {
        get
        {
            return Text_ ?? (Text_ = "hello");//line B
        }
    }

    private int? Num_;
    public int Num
    {
        get
        {
            return (int)(Num_ ?? (Num_ = 42));//line C
        }
    }
}

我正在使用 Visual Studio 2010 来获取代码覆盖率结果。它表明 B 线被完全覆盖,而 C 线被部分覆盖。我希望 B 线也被部分覆盖,而不是被完全覆盖。 为什么代码覆盖率结果显示B行被完全覆盖了?

为了证明它对 Num 属性“正确”工作,取消注释行 A 并运行覆盖。它应该显示 C 行完全被覆盖。

当我将代码重写为更详细的形式(见下文)时,它可以正常工作并报告 Text_ 被部分覆盖。为了简洁起见,我更喜欢使用前者,并且想知道这两种形式是否也等价。提前致谢。

if (Text_ != null)
{
    return Text_;
}
else
{
    return Text_ = "hello";
}

【问题讨论】:

    标签: c# visual-studio-2010 code-coverage


    【解决方案1】:

    Nullable<T> 上的 ?? 在编译器中扩展为更复杂的东西,即

    a ?? b
    

    真的

    a.HasValue ? a.GetValueOrDefault() : b
    

    现在,由于 a 在唯一一次执行时为空/空,因此从未调用过 a.GetValueOrDefault()。使用字符串(或任何平面引用)时的底层代码更简单。

    实际上,只需调用两次即可消除此问题:

    Console.Write(x.Text); // first call; performs init
    Console.Write(x.Text); // test once initialized
    Console.Write(x.Num); // first call; performs init
    Console.Write(x.Num); // test once initialized
    

    【讨论】:

    • 知道了。我应该更深入地研究我使用的语法糖,反正我的前提是错误的。
    【解决方案2】:

    如果不进入这一行生成的 IL,我会怀疑编译器做了一些内部优化,导致你的“B 行”被视为单个语句。

    这两个语句的主要区别在于 B 行引用一个对象,而 C 行使用了对Num_.Value 的简写引用。


    一般来说,“100% 代码覆盖率”绝对不值得强调——正如这个例子所表明的那样,无论如何,有时检测是错误的。重要的是覆盖了大部分代码,至少是通过业务逻辑的主要执行路径。

    覆盖范围不能替代其他人的代码审查。

    【讨论】:

    • 确实不值得强调 100% 的覆盖率这是我老板想要的,所以我打算为我无法覆盖的部分证明自己的合理性。如果不被接受,我也不会接受在这里工作太久。
    猜你喜欢
    • 2016-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-17
    • 2011-10-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多