2008年03月06日
_ ランダムテストの使い方
ランダムテストというものがあります。 プログラムをテストするにあたってランダムな入力を使うという ものです。テスト入力作を作るにはコーナーケースをできるだけ 網羅することが重要ですが、人手でそれをするのは難しいことです。 そのため入力はランダムにしてテスト数を増やすことでそれに対応 しようというのがランダムテストの基本的な考えかたです。 詳しくは QuickCheck などを参照、ってことでいいんでしょうか。
さて、ここで問題になるのがどのようにしてプログラムの出力を 検証するかです。ランダムな入力をプログラムに食わせるだけ ではテストにはなりません。その出力の正しさを判定する必要が あります。しかし、ランダムな入力に対する出力を生成できる プログラムというのはまさにそのテスト対象に他なりません。 テストをするためにはテスト済みのプログラムが必要、となって しまうわけです。これでは話になりません。ではランダムテストを 有効活用するためにどうすればよいのでしょうか。
一つの方法としては、出力結果が満たすべき条件をうまく考えて それを検証する方法があると思います。 例えば、ソートプログラムのテストをすることを考えましょう。 すると、要素が3個の配列を昇順ソートした結果が満たすべき性質として
- 出力の要素は3個でなければならな
- 出力が [x, y, z] と書きあらわされるなら x <= y かつ y <= z でなければならない
などといった条件をチェックするのです。こうすればランダムな入力 に対する検証が可能になります。
もう一つの方法として、より簡単で自明だが遅いという実装 の出力と比較する方法です。やはりソートプログラムのテストを することを考えましょう。この場合はまずバブルソートあたりを 実装してしまいます。で、その後目的のソートプログラムを 書き、それの出力とバブルソートの出力を比較するのです。 これなら入力がランダムでもテスト可能です。別の例として、 GPGPUのような高速だが特殊なプログラミングが必要という ものを考えます。この場合普通のCで別実装を書いて それを比較するという方法があります。 特殊なプログラミングのための処理系やハードウェアの挙動に 難しい点がある(高速性のためにわかりやすさが犠牲になっている というのはありそうな話です)という場合に特に有効でしょう。
ただ、これらの方法にも問題はあります。一つ目の方法では 例えばn個の配列に対し0がn個という出力を得られる プログラムでもテストが通ってしまいます。また、 簡単に検証できる条件なるものが常にあるとは限りません。 ソートのようなアルゴリズム的な問題の 場合には比較的そのような条件が見いだしやすいのですが、 世の中そういうプログラムばかりではありませんし。
二つ目の方法にしても、より簡単で自明な実装なるものが 常にあるとは限りません。世の中にはバブルソートを実装 するような仕事だってあるのです。 簡単な実装のほうが間違っていたらどうしようもないという 問題もあります。
とまあランダムテストは時と場所をかなり選びますが、 うまくはまれば非常に役にたちます。 二つ目の方法は私が実践しているので、ある程度うまくいくことは 保証できます。たいしたことのない文章ですが、なんらかの 役に立ってくれればありがたいことです。
2008年03月14日
_ Pencil Bullet
ここ1年くらい作っていたSTGを公開しました。実際的な部分を半分以上作って くれた森くんや音楽作ってくれた原くん、テストしてくれたKMCのみなさまに感謝。
(追記)公開してから言われた(思った)ことだけどなんかごりおしできる手段を 用意しときゃよかったかな。
2008年03月17日
_ Rubyのリフレクションとか
cuzicさんに、 この前Ruby勉強会@関西で話したリフレクションの話のような ことをまとめた文章ない?と聞かれたので、あちこちにちらばって いる私の書いた文章をちょっと探してみました。
- Rubyのproc Symbol#to_procとか
- Rubyに型チェック機構をつけてみる
- 手続きオブジェクトとブロック
- __send__とMethodクラス
- Module#define_method
- 変数/定数
- instance_eval, module_eval
- クラス階層関連
- この前のRuby勉強会@関西の発表資料
あと参考資料としてRHGをよくあげていますが、それは何故かというと 実装を見たほうが話が簡単であることがよくあるからです。 Rubyの仕様は一貫性よりも便利さを優先して決められた部分がありますし、 def … endの中のdef … endのようにどう決めてもあまり自然ではないが なんらかの動作が必要なので仕様が決まっている、なんていうのもあります。 コンテキストまわりは特にそういう傾向があります。で、そういう場合は 論理的な整合性を考えるより実装を見たほうが早いといえます。 Rubyの実装は日々変化するのでどこまで有効か、という話もありますが そこに注意すれば実装を見るのは有効な手段です。
_ LinuxでWindowsの実行ファイルを作ったりする話
Linux上でDで書いたプログラムからWindowsの実行ファイルを作る場合、gdcでクロスコンパイラを作るより wineでdmdを動かしたほうが簡単だったりします。このテクニックはshinhさんに教えてもらいました。 SDL+OpenGLくらいなら性能を気にしなければ実行テストもwineでできます。
またexerbでRubyのプログラムを作るときには、Linux上でもexerbが動くのでそれを利用すれば簡単に できます。これで作った実行ファイルもwineで動くので、簡単なテストならちゃんと動きます。 Visualu Rubyもwineでちゃんと動きます。
といったことを利用してPencil-BulletのWindows版はWindowsをほとんど使わずに作成されました。 正直VM上にWindowsを動かしたほうが簡単な気もしますが結構なんとかなるものです。