[英]Weird test coverage results for iterator block, why are these statements not executed?
我正在使用dotCover來分析我的單元測試的代碼覆蓋率,並且我得到了一些奇怪的結果......我有一個迭代器方法,覆蓋范圍不完整,但是未涵蓋的語句只是結束括號在方法的最后。
這是我正在測試的方法:
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沒有處理調查員,但如果我在actual
做一個foreach,我會得到相同的結果。
至於第二個未覆蓋的右括號,我不知道它代表什么......我猜這與編譯器如何轉換迭代器塊有關。
任何人都可以了解這兩個“陳述”是什么,為什么它們沒有被執行?
編輯:Peter提出了一個非常好的問題:上面顯示的結果是在調試版本上運行測試時獲得的。 如果我在發布版本上運行測試, CommonPrefixImpl
方法的覆蓋率是100%,因此它可能與編譯器優化有關。
迭代器方法的一個問題是編譯器生成一個相當大且復雜的狀態機來管理迭代器方法中代碼的延遲執行。 這通常會產生一兩個類。 這些類是為了處理一般情況而不是你的特定情況,因此可能至少有一些從未使用過的代碼。 您可以通過使用ILSpy,JustDecompile或Reflector等工具查看程序集來查看生成的內容。 它將顯示由C#編譯器生成的程序集中的類(通常包含'<'的類名等)
探查器知道的是PDB如何與您的代碼關聯,盡管您編寫的所有代碼都可能被執行,但仍有可能並非所有編譯器生成的代碼都被執行。 分析器可能不知道這一點,只是說某個特定迭代器方法的某個百分比(小於100)被執行了。
可能產生的一件事是異常處理代碼。 因為編譯器不知道你的代碼不會或者可能不能生成異常,所以它仍然會生成代碼來補償異常 - 它需要保持它的狀態不被破壞。 我敢打賭,如果你包含一種方法在基於某個標志的迭代器方法中的各個地方拋出一個異常,並且運行該方法兩次(一次沒有異常,一次在同一次運行中有異常),百分比會有所不同 - 可能更高因為生成的異常處理代碼將被執行。
“似乎”未執行的方法結束的事實可能是因為該代碼是狀態機中執行的不同方法的一部分,並且編譯器從不生成從生成的代碼到類中的代碼的關聯。
更新:為了更好地理解編譯器正在做什么,並查看它生成的代碼類型的示例,請參閱C#規范中的第10.14節迭代器 ( http://www.microsoft.com/en-us/download/details) .aspx?id = 7029 )
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.