对于迭代器块古怪的测试覆盖率结果,为什么这些语句不执行?(Weird test coverage r

2019-07-30 22:15发布

我使用dotCover来分析我的单元测试代码覆盖率,并且我得到一些奇怪的结果......我有一个iterator方法,其覆盖范围是不完整的,但没有覆盖的语句是在结束括号在该方法的结束。

下面是我测试的方法:

    public static IEnumerable<T> CommonPrefix<T>(
        this IEnumerable<T> source,
        IEnumerable<T> other,
        IEqualityComparer<T> comparer)
    {
        source.CheckArgumentNull("source");
        other.CheckArgumentNull("other");

        return source.CommonPrefixImpl(other, comparer);
    }

    private static IEnumerable<T> CommonPrefixImpl<T>(
        this IEnumerable<T> source,
        IEnumerable<T> other,
        IEqualityComparer<T> comparer)
    {
        comparer = comparer ?? EqualityComparer<T>.Default;

        using (IEnumerator<T> en1 = source.GetEnumerator(),
                              en2 = other.GetEnumerator())
        {
            while (en1.MoveNext() && en2.MoveNext())
            {
                if (comparer.Equals(en1.Current, en2.Current))
                    yield return en1.Current;
                else
                    yield break;
            }
        } // not covered
    } // not covered

单元测试:

    [Test]
    public void Test_CommonPrefix_SpecificComparer()
    {
        var first = new[] { "Foo", "Bar", "Baz", "Titi", "Tata", "Toto" };
        var second = new[] { "FOO", "bAR", "baz", "tata", "Toto" };

        var expected = new[] { "Foo", "Bar", "Baz" };
        var actual = first.CommonPrefix(second, StringComparer.CurrentCultureIgnoreCase);
        Assert.That(actual, Is.EquivalentTo(expected));
    }

和覆盖率结果:

我假设的右括号using块实际上是对呼叫Dispose的统计员; 但随后,它为什么不执行? 我首先怀疑NUnit的未处置的枚举,但我得到了同样的结果,如果我做一个foreach的actual

而对于第二未覆盖右括号,我不知道它代表什么?我想这是关系到编译器是如何将迭代器块。

任何人都可以阐明这两位“声明”有一些光,为什么不执行他们?


编辑:彼得提出了一个很好的问题:在运行调试版本的测试时,上面显示的结果获得。 如果我运行一个发布版本的测试,覆盖CommonPrefixImpl方法是100%,所以它可能涉及到编译器优化。

Answer 1:

一个与迭代方法的问题是,编译器产生一个相当大的和复杂的状态机来管理迭代方法中的代码的延迟执行。 这通常产生一个或两个类。 这些类是为了对付一般的情况下,而不是你的具体情况,所以可能有至少有一个位代码,从未使用过。 你可以看一下通过观察与像ILSpy,JustDecompile或反思的工具组件产生的。 它会显示在由C#编译器(通常含类名“<”,等)的生成组件的类

什么探查知道是PDB同事对你的代码,尽管所有你写可能被执行的代码,仍然有,并非所有的编译器生成的代码的执行得到了一个可能性的可能性如何。 探查器可能不知道这一点,简单地说,一个特定的iterator方法的一定比例(小于100)执行的原因。

其中一个可能如何产生的东西是异常处理代码。 因为编译器不知道你的代码将无法或可能无法生成异常它仍然会生成代码,以弥补一个例外 - 它需要保持它成为腐败的状态。 我敢打赌,如果你提供一个途径基于一些标志扔在各个地方的异常在你的迭代方法和运行方法两次(一次没有例外,一旦在同一个运行异常)的百分比会有所不同 - 可能更高因为那样的话所产生的异常处理代码会被行使。

该方法的终结“似乎”不被执行的,这可能是因为该代码是在状态机不同的方法被执行和编译器在你的类也永远不会生成从生成的代码的代码关联的一部分。

UPDATE:得到一个更好地了解编译器做的和看到(它产生见在C#规范10.14迭代器类型的代码示例http://www.microsoft.com/en-us/download/details的.aspx?ID = 7029 )



文章来源: Weird test coverage results for iterator block, why are these statements not executed?