2017-04-19 100 views
1

我正在使用gcov/lcov進行googletest單元測試的覆蓋率分析。某些googletest宏的覆蓋率分析顯示,當分散在多行時顯示不完整的覆蓋率 - 爲什麼?

一個反覆出現的問題是,覆蓋率報告在某些googletest宏的測試代碼中顯示未覆蓋的行,當宏分佈在多行時。

我知道gov/lcov不可能比單行更準確,但我對我所看到的行爲感到困惑。有人可以解釋這個嗎?小例子:

#include <gtest/gtest.h> 

TEST(coverage,incomplete) 
{ 
    // Every second line in every invocation here will show up as uncovered: 
    EXPECT_NO_THROW(40 + 
        2); 
    EXPECT_NO_THROW(40 + 2 
       ); 
    EXPECT_NO_THROW(40 + 2) 
    ; 
} 

TEST(coverage,complete) 
{ 
    // This test does not show uncovered lines 
    EXPECT_NO_THROW(40 + 2); 
    EXPECT_EQ(40 
      + 
      2 
      , // even though this is spread over several lines 
      42 
      ) 
    ; 
} 

如何覆蓋分析做:

g++-4.8 -Igtest/googletest/include/ --coverage -o coverage_macropp coverage_macropp.cpp gtest/googletest/make/gtest_main.a -pthread 
./coverage_macropp 
lcov --capture --directory . --output-file coverage.info 
genhtml --demangle-cpp coverage.info --output-directory coverage 

在Web瀏覽器的覆蓋率分析會再展線7,9,和11發現:

 Line data Source code 

    1    : #include <gtest/gtest.h> 
    2    : 
    3   5 : TEST(coverage,incomplete) 
    4    : { 
    5    : // Every second line in every invocation here will show up as uncovered: 
    6   1 : EXPECT_NO_THROW(40 + 
    7   0 :     2); 
    8   1 : EXPECT_NO_THROW(40 + 2 
    9   0 :     ); 
    10   1 : EXPECT_NO_THROW(40 + 2) 
    11   0 :  ; 
    12   1 : } 
    13    : 
    14   5 : TEST(coverage,complete) 
    15    : { 
    16    : // This test does not show uncovered lines 
    17   1 : EXPECT_NO_THROW(40 + 2); 
    18   1 : EXPECT_EQ(40 
    19    :    + 
    20    :    2 
    21    :    , // even though this is spread over several lines 
    22    :    42 
    23    :   ) 
    24   1 :  ; 
    25   4 : } 

爲什麼?爲什麼EXPECT_EQ宏不受影響?

+0

這取決於gcov如何分析其輸入,並可能取決於如何定義宏(例如,它們是否粘貼令牌)。所以那兩個地方要尋找解釋。 – Peter

回答

1

這是一個引人入勝的調查。看着這些宏,我已經瞭解了關於switch/case的事情,並且轉到了,我不知道是可能的。

但是,行爲差異的原因來自if/else結構,它們的共同之處在於其他分支永遠不會被執行,但是不同的是編譯器是否已經知道,這些分支永遠不會被執行。

首先,在源代碼分散在多個行宏的預處理程序產生(只要它的問題在此問題)編譯器下面的代碼,其覆蓋面分析:

if (condition) statement1; else statement2 


    ; 

而且很顯然,覆蓋率分析器gcov以分號分隔線作爲代碼行進行計數,並在執行else分支中的statement2時考慮執行。

現在,重現覆蓋分析的差異,如問題觀察,考慮這個例子程序:

#include <stdio.h> 
#include <time.h> 

int main(int, char*[]) { 
    const bool true_1 = true; 
    const bool true_2 = time(NULL) != 0; 

    if (true_1) 42; else printf("hello\n") 
        ; 
    if (true_2) 42; else printf("hello\n") 
        ; 
    return 0; 
} 

true_1true_2總是爲真(在我的有生之年,如果我不亂用電腦'時鐘),但在true_1的情況下,編譯器知道它,而對於true_2,它不知道。 (是的,我可能會找到一個更安全的true_2初始化程序,現在可以使用。)

還要注意if-分支中的語句什麼都不做,但else分支中的語句會產生副作用。

該方案的對gcov/LCOV覆蓋率分析是這樣的:

 Line data Source code 

    1    : #include <stdio.h> 
    2    : #include <time.h> 
    3    : 
    4   1 : int main(int, char*[]) { 
    5   1 : const bool true_1 = true; 
    6   1 : const bool true_2 = time(NULL) != 0; 
    7    : 
    8    : if (true_1) 42; else printf("hello\n") 
    9    :      ; 
    10   1 : if (true_2) 42; else printf("hello\n") 
    11   0 :      ; 
    12   1 : return 0; 
    13    : } 

因爲編譯器已經知道true_1是真實的,else分支,因此,9號線,不考慮覆蓋分析。編譯-O0時甚至是這樣。

然而,該程序中的第11行被認爲用於覆蓋率分析,因爲true_2僅在運行時才爲人所知。如果我還在else分支中使用了另一個dummy語句,或者甚至是一個已知沒有副作用的函數調用,如sin(7)而不是printf(「hello」), ,那麼這條線也不會計入gcov覆蓋率分析。

到目前爲止,對於完整的正式報道,如果測試結果在編譯時不爲人知,我必須將googletest宏限制爲單一源代碼行。

+0

好抓!制定得非常好。我認爲你應該接受你自己的答案。 – Jonas

相關問題