coverage測定の難しさ

まずは以下をちらっと見て欲しい.
http://ikda.net/cjemma/20051000/mysql-connector-java-5.0.0-beta-coverage/coverage.html

これは現在のConnector/Jの最新版(ver5.0系)を使ってテスト網羅率を計測するツールEmmaを実行した際のアウトプット.このEmmaというツールを通してJUnitのtestsuiteを実行することでこういうのが得られる.

さてパッと見、実装コードベースで57%しかテストが網羅されていないように見える.まずは「こりゃちょっと不味いんじゃないのか」と思うわけだ.

もう少し見てみよう.こちらはConnector/Jの中でも中心的な役割を行うクラス群が実装されている"com.mysql.jdbc"パッケージ.
http://ikda.net/cjemma/20051000/mysql-connector-java-5.0.0-beta-coverage/_files/6.html

クラス名                クラス      メソッド        ブロック            コード行
Connection.java         75%  (3/4)  37%  (111/302)  52%  (3747/7154)    56%  (939.5/1687)
ResultSet.java          100% (1/1)  58%  (136/236)  53%  (5345/10152)   59%  (1185.9/1994)
Statement.java          50%  (1/2)  75%  (46/61)    65%  (1525/2358)    69%  (355/511)
PreparedStatement.java  50%  (2/4)  62%  (51/82)    43%  (2369/5548)    46%  (524.8/1129)
CallableStatement.java  100% (4/4)  30%  (36/121)   45%  (1031/2287)    48%  (266.8/552)

JDBC API的にメジャーなクラスを見てみると,コード行ベースでおよそ50%から60%.やっぱりこりゃ不味いと思うのだけれども,もう少し見てみるとそうはなかなか一刀両断できない事情というのが見えてくる.

以下はConnectionクラスの詳細情報.
http://ikda.net/cjemma/20051000/mysql-connector-java-5.0.0-beta-coverage/_files/42.html

Connectionクラスは先ほどの統計では未テストなメソッドが63%もあることになっているけれども,ここを見るとテストされていないメソッドは実装コードが1行から2行のただのラッパーメソッドが占めていることが分かる.要するにMark Matthews氏的にはこれらのメソッドは今まで放置対象であったということなのだが,これらのメソッドはやっぱりテストされるべきだろうか?

いまの僕の考えでは,この辺りは放置したままでよいと思う.もちろん僕も日本での開発経験の中で,ただのアクセッサメソッド(getterとsetter)に対してもテストコードを書いていたことがある.しかしこれまで見たことのあるバグで,こういったメソッドがテストされていないことが原因で起きていたものは,無い.こうやってCoverageツールで数字が出てしまうとさも数字を上げるためにどうにかしないといかんなという気が出てきてしまうのだけれども,同じ時間を使うならもっとバグ潰しに対して有意義な使い方をしたい.

Connectionクラスのメソッドごとにもう少し見てみる.例えばcanHandleAsServerPreparedStatementメソッドなんてどうだろう.コード網羅率が"7.7/37"となっているので30行ほどテストコードを追加する余地がある.
http://ikda.net/cjemma/20051000/mysql-connector-java-5.0.0-beta-coverage/_files/42.html#c5

しかしよく見てみるとこれも放置したほうが良さそうだ.赤くハイライトされている行がtestsuiteの実行時に実行されなかったコードなのだけれども,よく見ると"if (!versionMeetsMinimum(5, 0, 7) "によってfalseとなっために実行されていないのが理由のようだ.

versionMeetsMinimumというメソッドはConnector/Jではよく使われているメソッドで,MySQLサーバのバージョンを確認するためのものだ.例えばver5.0.0で追加されたストアドプロシージャのテストをver4.1.14に対して行うのはナンセンスなのでそのテストを行わないようにするために回避したり,あるいは本体の方で言うと認証プロトコルがver4.0系とver4.1系以降では違うわけだけどそれぞれに対応したロジックを走らせるようにするために使用されたりしている.

MySQLサーバのver5.0系は既にver5.0.13になっており,今回testsuiteを実行した際に起動しておいた僕の環境のMySQLもver5.0.13だった.もしこの部分のコードを通るようにしようとするとver5.0.7以前のMySQLサーバを起動しておく必要がでてきてしまう.そしてもちろん,起動しておくサーバのバージョンを変えれば,今度はそれが原因となって別の部分のコードが実行されなくなるというエンドレスな状態に陥る.

ではEmmaのアウトプットは全く役に立たないかというとそうではない.例えばreportMetricsメソッドを見て欲しい.
http://ikda.net/cjemma/20051000/mysql-connector-java-5.0.0-beta-coverage/_files/42.html#c3
これは接続プロパティの指定の有る無しで実行されるか否かがわかれるものであり,今書いたようなサーバのバージョンには依存しない話だ.また実はこのgetGatherPerformanceMetricsというのは,9月頭あたりにバグレポートがあがっていてこの間僕がバグ検証したまさにそのものだ.もし3ヶ月前にこの部分の未実行を発見してテストしていたらバグレポートがあがる前にバグをつぶせていたかもしれない.

そういう意味ではEmmaも役に立ちうる.しかしこれは一つ一つ地道に見ていかなければ分からないことだ.Coverageはまず情報提供として重要だし,それを使って品質を高める(バグを減らす)ことも重要なのは十分理解しているけれども,でてくる数値自体もほんとうの問題をそのまま反映しているとは言い切れないし,すぐに簡単に有効活用できるってものでもないので,難しいですね〜という愚痴ともなんともつかないエントリを書く顛末と相成った.

そんな感じです.がんばります.



追記:
というわけでさっそくgatherPerformanceMetricsを指定して接続するテストコードをConnector/Jのtestsuiteに追加してみた.

結果は何とテスト済み実装コード行数が+120くらいUP.Connectionクラスのコード行数網羅率は56%から63%に+7%もUP.どうも網羅済みメソッドが予想外に4つも増えているのが理由か.まあ他にもいろいろプロパティ指定してるからな.

ただのラッキーパンチっぽいんだけど,何だかんだで数字が挙がればそれなりに何かうれしいw