はじめに
初期ファイナル・ファンタジーの伝説的プログラマ,ナーシャ・ジベリの「早撃ち」エピソードを知っていますか? 彼はヒーローのようにさっそうと現れ,どんなプログラムでも電光石火で書いてしまいます。「見てくれの悪さは気にしねえ。誰よりも早くやってやるぜ」。やがていくつかの伝説を残し,彼もプロジェクトを去るときがやってきました。残った同僚たちは困りました。彼の超絶プログラムは彼にしか理解できず,バグがあっても修正できないのです。それに,変更しようとすると動かなくなってしまいます。「ナーシャ,カムバック!」でも彼はもう戻ってきません……。
こうした悲劇を防ぐ方法の1つがソフトウェアテストです。OpenFlowコントローラのように動作シーケンスが複雑なソフトウェアが壊れていないことを確認するためには,ソフトウェアにより自動化されたテストが有効です。それに,きちんとしたテスト一式があればプログラム本体の理解もしやすく,修正も簡単です。
TremaはOpenFlowコントローラをテストするためのテストツールが充実しています。今回はこれを使って,簡単なコントローラ(リピータハブ)をテストファースト形式で実装していきます。
ではさっそく実際の例を見ていきましょう。
リピータハブの設計
まずは,リピータハブがどのように動作するかを説明しましょう。ホスト3台のネットワークを考えてください。あるホストからパケットを送信すると,リピータハブは入ってきたパケットを複製してほかのすべてのホストにばらまきます。
OpenFlowプロトコル的に何が起こっているかを図1に示します。host1がパケットを送信すると,スイッチからコントローラにpacket_inが起こります。ここでコントローラは「今後は同様のパケットをほかの全ポートへばらまけ(FLOOD)」というflow_modを打ちます。また,packet_inを起こした最初のパケットをほかのすべてのホスト(host2 とhost3)に明示的にpacket_outで届けます。
最初のテスト
ではさっそく,リピータハブのテストコードを書いていきましょう。TremaのテストフレームワークはRubyのユニットテストツールRSpecと統合されています。まだインストールしていない人は,「geminstall rspec」でインストールしてください。また,TremaのAPIについては,こちらを参照してください。
テストコードの最初のバージョンはリスト1のとおりです(spec/repeater-hub_spec.rb)。最初の行は,テストに必要なTremaのライブラリを読み込みます。describeで始まるdo…endブロックはテストの本体で,RepeaterHubコントローラのふるまいをここに記述(describe)する,という意味です。
リスト1 リピータハブのテストのひな形
require File.join(File.dirname(__FILE__), "spec_helper")
describe RepeaterHub do
end
RepeaterHubを定義していないのでエラーになることはわかりきっていますが,テストを実行してみましょう。次のコマンドを実行すると,Tremaを起動したうえでspec/repeater-hub_spec.rb(リスト1)のテストを実行します。
$ rspec -fs -c ./spec/repeater-hub_spec.rb
.../spec/repeater-hub_spec.rb:3: uninitialized constant
RepeaterHub (Name Error)
予想どおり,定数RepeaterHubが未定義というエラーで失敗しました。エラーを修正するために,RepeaterHubクラスの定義を追加してみましょう(リスト2)。
リスト2 空のRepeaterHubクラスを追加してNameErrorを修正
require File.join(File.dirname(__FILE__), "spec_helper")
class RepeaterHub < Controller ← 空のクラスを追加した
end
describe RepeaterHub do
end
本来,コントローラクラスは独立した.rbファイルに書きますが,今回は簡便さを優先し,テストコード上に直接書いているので注意してください。それでは実行してみましょう。今度はパスするはずです。
$ rspec -fs -c spec/repeater-hub_spec.rb
No examples found.
Finished in 0.00003 seconds 0 examples, 0 failures
やった! これで最初のテストにパスしました。
このようにテストファーストでは,最初にテストを書き,わざとエラーを起こしてからそれを直すためのコードをちょっとだけ追加します。テストを実行した結果からのフィードバックを得ながら「テスト書く,コード書く」を何度もくりかえしつつ最終的な完成形に近づけていくのです。

