CodingFirst

C言語、Perl、JavaScript、最近はPythonも。出来上がったものより、プログラムを書くことが好き。あと、スイーツ。

スポンサーサイト

  • このエントリーをはてなブックマークに追加
  • web拍手 by FC2
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

GCCでC言語のラインカバレッジ。ちょっと怖いぞ。

  • このエントリーをはてなブックマークに追加
  • web拍手 by FC2

gcc(gcov)のラインカバレッジを試した(C言語)。

そもそも、ラインカバレッジに関しては、
「カバレッジとしてはちょっと弱い」程度の知識しかなかった。
だから、どう弱いのか実感したかった。
ただし、やって見た結果は、たしかにラインのカバレッジだ!...ではあったけどね...

まず、おさらい。カバレッジの測り方。
作成したソース gcov-test-line.c をコンパイル、実行して、gcovで集計する。

$ gcc -g --coverage gcov-test-line.c && ./a.out && gcov gcov-test-line.c
P
P
P
P
P
File 'gcov-test-line.c'
Lines executed:93.75% of 64
gcov-test-line.c: 'gcov-test-line.c.gcov' を作成しています

できた gcov-test-line.c.gcov を見る。

        -:    0:Source:gcov-test-line.c
        -:    0:Graph:gcov-test-line.gcno
        -:    0:Data:gcov-test-line.gcda
        -:    0:Runs:1
        -:    0:Programs:1
        -:    1:#include <stdio.h>
        -:    2:

        1:   74:int main(int c,char*v[]){
        1:   75:  line1_ok(0);
        1:   76:  line2_ok(0);
        1:   77:  line3_ng(0);
        1:   78:  line4_ok(0);
        1:   79:  line5_ok(0);
        1:   80:  line6_ok(0);
        1:   81:  line7_ng(0);
        1:   82:  line8_ok(0);
        1:   83:  line9_ng(0);
        1:   84:  line10_ok(0);
        1:   85:  line11_ok(0);
        1:   86:  line12_ok(0);
        1:   87:  line13_ok(0);
        1:   88:  return 0;
        -:   89:}

冒頭とmain関数付近。特になし。

        1:    7:void line1_ok(int i){
        1:    8:  if(i==0||i==1){
        1:    9:    puts("P");
        -:   10:  }
        1:   11:}

複数の条件があり、実行されない条件(i==1)がある場合。
これはラインカバレッジとしては、OKと判定される。
やはり、文字通り、行をちょっとでも実行したらOKのようだ。

        1:   12:void line2_ok(int i){
        1:   13:  if(i==2){puts("N");}
        1:   14:}
        1:   15:void line3_ng(int i){
        1:   16:  if(i==2){
    #####:   17:    puts("N");
        -:   18:  }
        1:   19:}

if文の条件不成立の場合。
13行目のように 1行でまとめてしまえば OK。
複数行にすると実行されない扱いになる。

        1:   20:void line4_ok(int i){
        -:   21:  if(0){
        -:   22:    puts("N");
        -:   23:  }
        1:   24:}

意外にも if(0)の場合はラインカバレッジは OK。
特に最適化をかけたつもりはないので、明らかに実行されないパスは
OKという事なのだろう。

        1:   25:void line5_ok(int i){
        -:   26:  int j;
        1:   27:  j=(i==0)?0:1;
        1:   28:}

3項演算子による代入。
(i==0)のフォルスパスが実行されないが、ラインカバレッジ的には OK。
だんだんノリがわかってきた。

        1:   29:void line6_ok(int i){
        1:   30:  switch(i){
        1:   31:    case 0:puts("P");break; default:puts("N");break;
        -:   32:  }
        1:   33:}
        1:   34:void line7_ng(int i){
        1:   35:  switch(i){
        -:   36:    case 0:
        1:   37:      puts("P");
        1:   38:      break;
        -:   39:    default:
    #####:   40:      puts("N");
    #####:   41:      break;
        -:   42:  }
        1:   43:}

switch - caseで実行されないパスがある場合。
1行にまとめてしまえば OK。

        1:   44:void line8_ok(int i){
        -:   45:  int j;
        1:   46:  for(j=0;j<i;j++){puts("N");}
        1:   47:}
        1:   48:void line9_ng(int i){
        -:   49:  int j;
        1:   50:  for(j=0;j<i;j++){
    #####:   51:    puts("N");
        -:   52:  }
        1:   53:}
        1:   54:void line10_ok(int i){
        1:   55:  while(i>0){puts("N");}
        1:   56:}

forもwhilieも同じ。1行ならOK

        1:   57:void line11_ok(int i){
        1:   58:  while(i>=0){
        1:   59:    puts("P");
        1:   60:    break;
        -:   61:    puts("N");
        -:   62:  };
        1:   63:}
        1:   64:void line12_ok(int i){
        -:   65:  do{
        1:   66:    puts("P");
        1:   67:    break;
        -:   68:    puts("N");
        -:   69:  }while(++i>=0);
        1:   70:}

whileやdo-whileの途中で強制breakした場合。
break以降の処理は通過しないが、ラインカバレッジは OK。

        -:    3:#define m1(i) if(i==3){\
        -:    4:  puts("N");\
        -:    5:  }
        -:    6:

        1:   71:void line13_ok(int i){
        1:   72:  m1(i);
        1:   73:}

複数行なマクロの場合。
連結してるから、ラインカバレッジは OK なのだろう。

以上から、
gcc(gcov)のラインカバレッジは確かにラインのカバレッジだった。
とにかく行をまとちゃえば OK と考えていいだろう。

実際、テストにたっぷり時間をかけられなかったり、
仕様変更が頻繁におきたりするときには
これくらいの粒度で丁度よいかなぁと思う。

だけど、これで慣れてしまうのは怖い。
なまじデータが計測できてるだけにこれ以上を目指さなくなるし、
カバレッジを上げる事が目的になって、かえってソースコードの品質が落ちてしまうような
そんな気がしてならない。


実例で学ぶGCCの本格的活用法―高機能コンパイラのオプション・コマンドを一つ一つていねいに解説 (TECHI―Embedded Software)実例で学ぶGCCの本格的活用法―高機能コンパイラのオプション・コマンドを一つ一つていねいに解説 (TECHI―Embedded Software)
(2006/07)
岸 哲夫

商品詳細を見る

ソフトウェアテスト入門 押さえておきたい<<要点・重点>>ソフトウェアテスト入門 押さえておきたい<<要点・重点>>
(2008/04/11)
ソフトウェア・テストPRESS編集部

商品詳細を見る

今回使ったソースコード

#include <stdio.h>

#define m1(i) if(i==3){\
  puts("N");\
  }

void line1_ok(int i){
  if(i==0||i==1){
    puts("P");
  }
}
void line2_ok(int i){
  if(i==2){puts("N");}
}
void line3_ng(int i){
  if(i==2){
    puts("N");
  }
}
void line4_ok(int i){
  if(0){
    puts("N");
  }
}
void line5_ok(int i){
  int j;
  j=(i==0)?0:1;
}
void line6_ok(int i){
  switch(i){
    case 0:puts("P");break; default:puts("N");break;
  }
}
void line7_ng(int i){
  switch(i){
    case 0:
      puts("P");
      break;
    default:
      puts("N");
      break;
  }
}
void line8_ok(int i){
  int j;
  for(j=0;j<i;j++){puts("N");}
}
void line9_ng(int i){
  int j;
  for(j=0;j<i;j++){
    puts("N");
  }
}
void line10_ok(int i){
  while(i>0){puts("N");}
}
void line11_ok(int i){
  while(i>=0){
    puts("P");
    break;
    puts("N");
  };
}
void line12_ok(int i){
  do{
    puts("P");
    break;
    puts("N");
  }while(++i>=0);
}
void line13_ok(int i){
  m1(i);
}
int main(int c,char*v[]){
  line1_ok(0);
  line2_ok(0);
  line3_ng(0);
  line4_ok(0);
  line5_ok(0);
  line6_ok(0);
  line7_ng(0);
  line8_ok(0);
  line9_ng(0);
  line10_ok(0);
  line11_ok(0);
  line12_ok(0);
  line13_ok(0);
  return 0;
}
スポンサーサイト


★☆★コメント★☆★

コメントの投稿

Name
Subject
Mail
URI
Comment
Pass
Secret 管理者にだけ表示を許可する

トラックバック

http://iyukki.blog56.fc2.com/tb.php/155-a9ba6b8c

 | HOME | 

Search

Recent Entries

Foot Print



Categories

Monthly

Recent Comments

Recent Trackbacks

Profile

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。