代碼覆蓋率是按百分比計算的,即 Visual Studio會告訴你,有百分之多少的產品代碼被覆蓋了,而且你也可以查看單個函數的代碼覆蓋率,如下圖所示:
在“代碼覆蓋率結果”列表里雙擊每個函數名,你可以看到具體的代碼覆蓋信息,青綠色的代碼是完全被覆蓋到的,紅色的代碼是從來沒有執行過的,而黃色的代碼表示這一行有一部分代碼被執行過—之所以說有一部分通常是因為一行代碼有多個判斷條件,有些條件執行了,有些卻沒有。如下圖所示:
代碼覆蓋率的實現原理
看到這里,是不是有點神奇?為什么執行過一些自動化測試用例,就可以查看代碼覆蓋率呢?它是怎么實現的呢?
實際上我們在“localtestrun.testrunconfig”窗口里面設置查看代碼覆蓋率那一步時,Visual Studio悄悄地修改了WildChar.exe,在原來的IL 代碼里添加了一些新的語句。
在解釋之前,我們先考慮代碼覆蓋率的意思,代碼覆蓋率的意思其實就是表明有多少行代碼被執行到了,因此首先要統計有多少塊代碼,然后再統計有多少塊代碼被執行了。什么叫代碼塊呢,代碼塊就是一段連續的代碼。例如在program.cs里面,下面這些代碼行組成一個代碼塊:
char[] result = new char[input.Length]; int resultIter = 0; ReverseStringPairImp(input, 0, result, resultIter); return new string(result); |
因為上面的代碼,如果不ReverseStringPairImpl 函數不拋出異常的話,就會連貫地執行下去,因為上面四行代碼可以看成是一塊代碼(或者說是一行代碼)。
而下面的代碼則可以看成是兩塊代碼:
if (indics[1] == 0) indics[1] = -1; else if (indics[1] > 0) break; |
要么是第一個if執行,要么第二個if 執行。
下面的代碼會有點意思,雖然是一行代碼,但是可以當作兩個代碼塊來看待:
while (inputIter < input.Length && input[inputIter] == ' ') |
1. 要么前面一個條件成立,后面的條件不成立,那么最后一個語句不執行;
2. 要么兩個條件都成立,最后語句執行;
3. 要么兩個條件都不成立,最后一條語句不執行。
由于第二個條件存在不被執行的機會—即我們設計的所有測試用例都導致第一個條件總是不成立,所以這也是為什么在顯示代碼覆蓋率結果的時候,上面那行代碼只有部分覆蓋到的原因。
有了代碼塊的概念之后,在實現代碼覆蓋率這個功能時,我們可以用一個大的布爾數組來保存有多少塊代碼被執行這個信息,而布爾數組的長度呢,就是程序的代碼塊的個數(因為一塊代碼可以看成一行代碼)。也就是說,我們可以把產品代碼手工修改成類似下面的樣子:
bool pathCovered[] = new bool[11]; // 11是統計下來程序里面代碼塊的個數 for ( int i = 0; i < pathCovered.Length; ++i ) pathCovered[i] = false; // while (inputIter < input.Length && input[inputIter] == ' ') inputIter++; firstblock: bool result = inputIter < input.Length; pathCovered[0] = true; if ( result ) { result = input[inputIter] == ' '; pathCovered[1] = true; } else { pathCovered[2] = true; goto secondblock; } if ( result ) { pathCovered[3] = true; inputIter++; goto firstblock; } secondblock: pathCovered[4] = true; int[] indics = new int[2] { inputIter, // first word begin index, 0 // second word begin index }; for (; pathCovered[5] = true, inputIter < input.Length; pathCovered[6] = true, ++inputIter) { pathCovered[7] = true; if (input[inputIter] == ' ') { pathCovered[8] = true; if (indics[1] == 0) { pathCovered[9] = true; indics[1] = -1; } else if (indics[1] > 0) { pathCovered[10] = true; break; } } } // 統計代碼覆蓋率信息 int covered = 0; for ( int i = 0; i < pathCovered.Length; ++i ) { if ( pathCovered[i] ) covered++; } return covered / pathCovered.Length; |
原文轉自:http://www.uml.org.cn/Test/201306262.asp