TDD はロストテクノロジー化しているか?

何故か、英語で CppUnit の解説を小一時間することになってしまったので、その後の展開的に残しておく。

使っている人は使っているらしいが

github のコードを見ると大抵のフレームワーク系のライブラリは、 test フォルダがあってテストプロジェクトがある。まあ、実際に自分でやってみると適当な xUnit を書かないと立ち行かない場合が多い(スタート時点の複雑さに追いつかない&後で混乱して修正コストが高くなる)のとで残しておくのと、ライブラリのマニュアル的なものとして残しておくと便利なのでちらっと書いておくとよい。

が、どこでどう間違ってしまったのか、様々な原因で身の回りに実務で TDD をやっている人は少ない…というかいない。これは主に業務アプリを作っている私だからなのか、最近はあまりであることが少なくなったのか分からないが、テストコードを書いている人は少ない。変わりに、従来通りの UI の打鍵テストをやったり、Excel で管理された単体テストや結合テストを繰り返している。

おそらく、XP のプラクティスと業務アプリ開発に取り入れるには「ペアプログラミングはコストが高い」、「UnitTest を継続的に使うにはコストが掛かる」があり、もうひとつ「単体テストをやると、単体テストのバグ票が出ない」かつ「単体テストの項目数が数えられない」というものがある。これは、2000年頃に XP/TDD を導入したときから言われてきたものだ。契約時に工数見積もりをするとき、「単体試験工程」を含ませてる必要があって、単体テストの項目数やバグ数という指標に引きずられてしまうというパターンである。まあ、そういう場合は

  • 単体テスト込みの製造工程/ガントチャートとする。
  • 単体テストの不具合票は出さない。

で押し切るのがベター。なんらかの QA 絡みで押し切られる場合には、不具合票自体をでっち上げるという手段をとる。

そんな訳で TDD は実質あまり広がらずに廃れてしまったものの、本質的に便利なところは便利だとわかっている人が使っている、という状態なのだろう。ちなみに言えば、UnitTest のフレームワークを使うか使わないかで、私的には工数的には倍以上異なる。MVVM パターンの解説のときにもよく言うのだが、

  • 内部ロジック(M-VM)部分をできるだけ多くして、UnitTest を使う。
  • UnitTest が適用しやすいクラス構造に徹する(できるだけモックを使わない)。
  • 適用外の場合は、通常の UI 打鍵で行う。

というスタイルが良い。TDD を適用しようとしたとき失敗するパターンが多いのが、すべての TDD を適用しようとするパターンである。どんな方法でも「適用可能な範囲」があるので、TDD で苦手な部分は多い。特に、ユーザーがいろいろなタイミングで打鍵するパターンは、TDD だけではうまくいかない場合がある(とはいえ、解析的に UnitTest を使うとうまくいくパターンも多い)。そのあたりを含めて、部分的に XP/TDD を取り入れればよいのである。

ちょっと変わった UnitTest フレームワーク

.NET Framework の場合は、Visual Studio で MS 謹製の UnitTest を使ったり、由緒正しい NUnit を使ったりする。Java の場合は JUnit だし、探せばたいていのプログラム言語に UnitTest フレームワークが用意されている。

UnitTest の基本は簡単で、

  1. テストコードを(できるだけ同じ言語で)プログラミングする。
  2. テストコードを何等かの形で実行する。
  3. テストの結果を自動判別する。

の 3 点があれば十分である。以前、Visual Test という GUI のテストを VB を使ってテストするフレームワークがあったがあまりはやらなかった。中身が C++/MFC で書かれていても、VB でテストしない駄目だったからだ。まあ、GUI の自動テストってのが難しいというのあるんだけど。

テストの実行環境は、できるだけ実環境と同じにあわせる。例えば、ガラケーの開発をしていたときには CPU の種類が異なるので、PC のテストとガラケー内のテストではずれが生じる可能性がある。ので、ガラケー内でテストが実行されるようにするのがベター、だがロジック的には PC でも十分だったりする。

結果を自動判別するのは、1,2,3 のサイクルを自動的に回すために必須である。昔 TDD 出る前に Excel で単体試験項目を書いて自動で動かす VBA を組んだことがあったが、結果は目検で行っていた。いま考えれば、結果を VBA で取り込んで Countif あたりで集計すればよかったのである。

そんなわけで、通常の PC あるいはサーバーで動く UnitTest はプログラム言語対応をそのまま使い、PC 以外の場合はちょっとした工夫が必要になる。

CppUnit

CppUnit – C++ port of JUnit – Browse /cppunit/1.12.1 at SourceForge.net
http://sourceforge.net/projects/cppunit/files/cppunit/1.12.1/

2008年で更新が止まっているが、これで十分。Visual C++, g++ で動くのでこれを使い続けている。一時期は更新結果が Green/Red になることが重要だったりしたが、実はそれは些末なところでしかない。本質は、All Success なのか Any Failure なのかにある。失敗したことが確認できて、どこでエラーになったか判別できればそれで十分である。

image

これは内部で FEM を計算するときの歪み関数をテストしているところだ。こういう科学計算の結果チェックに使える。

FsUnit

What is FsUnit?
http://fsprojects.github.io/FsUnit/

内部的には NUnit のラッパーなのだが、テストの書き方がちょっと異なる。たいていの xUnit テストは assertEqulas( 期待値, 実行値 ) という形でテストを書き連ねるのだが、FsUnit の場合は 実行値 |> should 期待値 というテストの書き方になる。期待値と実行値の語順が逆なのは関数型言語特融のカリー化/パイプを使っているため。この語順が便利かというと、実は結構混乱をしていて私の場合、CppUnit や NUnit の語順に慣れているのでよく間違う。

とはいえ、パイプを使うことで通常の assertEqulas 関数とは違った使い方ができる。特にパイプの間にログのフィルタを挟み込めるのは便利だ。バグ解析をするときに

実行値 |> dprint |> should be …

のように、適切な dprint を用意して挟み込めるようにするスタイルができる。

ArduinoUnit

先に書いた通り、組み込みシステムを作っているときは実機で動くような UnitTest を書くのがベストだ。Arduino の場合には Sketch と呼ばれるプログラム(実質、プログラムだ)を書いて動作させる。言語は C++ 風になっているので、ほぼ CppUnit が使える。ただし、 Arduino の sketch 自体が完全に C++ 準拠なのかどうかはわからないので、できれば Arduino 専用の UnitTest を使って、実行は Arduino 上でやったほうがいい。特に、GPIO をリアルタイムで制御するとか、センサーからの値を取得するとかは実機でしかできない(勿論、センサーからの値は毎回異なるので、assertEquals の対象としては使えない。センサーから読み込める/読み込めない、とか BLE 通信をするとか、そういう扱いになる)。

mmurdoch/arduinounit: ArduinoUnit is a unit testing framework for Arduino libraries
https://github.com/mmurdoch/arduinounit

まだ使ってみたことはないが、ひと通り AssertEquals が使えて結果がシリアル通信で送られてくるらしい。BLEやWiFi モジュールの通信系とかを作るときに便利そう。

Xamarin の UI Test App

Xamarin.UITest – Xamarin
https://developer.xamarin.com/guides/testcloud/uitest/
Xamarin.UITests クイック スタート | Xamarin : XLsoft エクセルソフト
http://www.xlsoft.com/jp/products/xamarin/uitest-quickstarts.html

Xamarin Test Cloud が必須っぽいのだが(テスト自体はローカルで実行できる?)、Android/iOS 上でテストをするツールである。これも試したことがないので記事を読む限り、昔の Visual Test に近いスタイルを取っている。UI コントロールに直接代入をする形になる。ただし、テストコード自体が C# であるのと、Xamarin 自体が C# で組む(F#/VB でも可能だけど)ので、テストフレームワークとして同じ言語を使える。スマートフォンのテストに特化しているので、ユーザーからの入力と画面キャプチャができるのがメリットだろう。

内部的には NUnit で動いているようなので、Xamarin.UITest.IApp と ITestServer を実装すればローカルで動かす限り Xamarin Test Cloud は必要ないのではないか?という作りになっている。勿論、Xamarin Test Cloud  自体は Android のいろいろな機種で動くというメリットがあるので、手元にある機種限定になるだろうけど。

Android Studio で UnitTest

AndroidStudioでUnitTestを行う | Anysense Blog
http://blog.anysense.co.jp/app/androidunittest/

こちらのほうは、由緒正しい JUnit を使った Android のテスト。こっちの UnitTest は Android Studio 上で動かすパターンなので UI を介在しない。ロジックなどをテストときに使う。

これも本来ならば、Android 実機上で動かしてログなどの形で結果が通知されるとよい。たぶん、テスト用の画面を作って「テスト実行」のボタンを押すと TestMain が起動されるという形にすればよいと思う。

Swift で UnitTest

Swift 2 + Xcode 7: Unit Testing Access Made Easy!!!!
https://www.natashatherobot.com/swift-2-xcode-7-unit-testing-access/

以前から、Xcode には test プロジェクトを作るか否かのスイッチはあるものの使ったことがない。まあ仕事がら執筆用のサンプルを作ることが多いので単体テストをやること自体が少ないのだが。

これも Android Studio と同じように Xcode 上でテストを実行するパターン。@testable というキーワードを使ってテストクラスを指定する(NUnit は属性を使ってテストクラスを指定する)。これも、実機の iPhone 上で動くことが望ましい。

参考文献

そんな訳で、実行環境が変わるとそれに追随して UnitTest のフレームワークも再作成される。が、もともと UnitTest のパターンは同じなので他言語で作ったテストパターン/知識は流用できる。つまり知識の蓄積ができる分野なのだ。

という訳で、ロスとテクノロジー化していると思われたら再入門し、知らなかったら「損」だよという形でお薦めする。

[amazonjs asin=”4894717115″ locale=”JP” title=”テスト駆動開発入門”]

ちなみに、私が最初に読んだ TDD の本はこれです。

[amazonjs asin=”4756136877″ locale=”JP” title=”Rubyを256倍使うための本 極道編”]

カテゴリー: 開発, TDD パーマリンク