トップ 最新 追記

follow ikegami__ at http://twitter.com

イネムリネズミ日記

いけがみを召喚するには、出現予定を参考にしてください。三週間前までにメールをくだされば、日程を追加するなどしてスケジュールに組み込むことができるかもしれません。勉強会や個人的な会合、中途採用面接などに応じます。日記に書かないことはこちら

2003|04|05|06|07|11|12|
2004|01|02|03|04|05|06|07|10|11|
2005|01|02|03|04|05|06|07|08|11|
2006|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|11|12|
2010|03|04|12|
2011|02|03|04|06|08|09|10|

2008-03-08 三色菫は考える思い [長年日記]

_ バグがでないのは良い知らせなのか

via バグがでないのは良い知らせなのか ー ありえるえりあ via [ThinkIT]第5回:品質管理

テスト工程においてバグがでないのは、品質が本当に良いのか、テストのやり方が悪いのかのどちらかです。

どちらか、なのでしょうか?まだ、要因はありそうな気がします。

以前から、このブログで述べていますが、「テスト=Input:(テスト対象プログラム, テストインスタンス), Output:Success/Fail, Body:テストコード」だと私は捉えています。この定義において、テスト工程においてバグが見付かることは次のように定義されます:

テスト対象プログラムとテストインスタンスを与えたところ、テストコードが Fail を返した

すると、テスト工程においてバグが見付からない、つまり、テストに成功するのは、

  1. テスト対象プログラムに間違いがない
  2. テストコードに間違いがあり、偶然 Success を返した
  3. テストコードに間違いがなく、かつ、テストインスタンスがテスト対象プログラムの間違いを指摘できなかった

のいずれかということになります。「間違い」という言葉の定義は曖昧なのですが、今日は特に触れません。長くなりますから。

ここで、具体例をあげることにしましょう。テスト対象プログラムは、正の整数 i を受け取り、 i 番目の素数を返すプログラムだとしましょう。 テストコードは、正の整数 n を受け取り n が素数か合成数かの判定をするプログラムです。テストインスタンスは、ある正の整数 j です。

テスト対象プログラムに間違いがなければ、どんなテストをしても成功するでしょう。(1) の場合です。テストコードに間違いがあり、偶然 Fail を返したときは目もあてられませんが、それは明らかにテスターが悪い。

(2) テストコードに間違いがあり、偶然 Success を返すケースはどうでしょうか。素数判定プログラムはとても簡単に書けますが、プログラマがアホだと合成数を受け取ったのに、「素数だ!」と答えるようなプログラムを書いてしまうかもしれません。それはありえる話です。大きな数が素数かどうかを判定するプログラムを作るのは自明ではありません。

最後に、(3) のケースです。こいつはやっかいさんです。テスト対象プログラムの間違いを指摘する j をどのように選べばよいのでしょうか。それは誰にもわかりません! j を小さい順に選べば、テストの実行時間は早く済みますが、どんな j がテスト対象プログラムの問題をあばきだすかは定義することができない問題です。(例外として、テスト対象プログラムが「帰納的実装」であれば基底段をテストするだけでよいのですが、そういうプログラムばかりではないのが現状ですね)

また、このテストコードは、「本当に i 番目なのか」についてはテストを行っていないことに注意してください。それは、別のテストコードで行うほうが、効率が良いのです。テストコードはできるだけ単純にして、合成するという方法が賢いです。

一般に、人間がテストインスタンスを作っていると、「『想定外』を想定していなかった」ということが起きてしまいます。そのために、テスト対象プログラムの間違いを指摘できないことがあります。これを「テストのやり方が悪い」と呼ぶことにすると、「人間がテストするテストのやり方は悪い」という結論に至ると思うのですが、僕の論理はどこかおかしいでしょうか。

ありえるえりあの井上氏はテスト工数を長くすることを提案しています。これにより、(2)テストコードの間違いに気がつく確率は高まるかもしれません。しかし、(3)テストコードが正しかったときに、どのようなテストインスタンスを与えればテスト対象プログラムの間違いを指摘できるか、は時間や人数では解決できない問題だと、いけがみは考えます。先ほどの簡単な具体例で見たように (3) の場合では可算無限な時間が必要です。

従来のテスト手法の多くは「表」によるテスト工程の視覚化を図っています。これにより、テストコードの種類を増やしたり、テスト対象プログラムの調べたい性質の個数を増やしていることが視覚化されます。が、個々のテストは (3) という、私に言わせれば「品質の良さをテストで決めることはできない」致命的な弱点が存在しています。ですから、表やバグ曲線などの視覚化をいくら用いたところで、「テスト」という方法に欠点がある以上、テスト対象プログラムの品質を議論する手法としては不適切です。

テストは、あくまで、テスト対象プログラムの間違いを heuristic に探すための手段だと考えるべきです。ソフトウエアの品質とは無関係です。

しかし、現実に立ち戻ると、テストをしないよりはしたほうがずっとましであり、テストを闇雲に行うよりは、なんらかの方針に基づいて行うほうがましなことは明らかです。表やグラフによる視覚化は、テストを行う者を助けます。視覚化はまだまだ改善の余地があります。たとえば、今ではアニメーションを行うことがずっと容易になりましたから、そういったアプローチもありうるでしょう。2D の表ではなく 3D の「物体」ならではの利点も考えられます。

最後に、現状で、いけがみが理想と思っているテスト手法について述べてみたいと思います。

テストコードに間違いがあるかないかを計算機が自動的に確かめることは不可能です。人手が必要です。ただし、計算機が何らかの形で援助することは可能です。たとえば型とか。C みたいな貧弱な型ではなくて、もう少し rich な言語の型を想像してください。

テスト対象プログラムの間違いを指摘するテストインスタンスを人間が考えるのは、人間の「うっかり」「思いすごし」「想定外」という本質において、無理だと言えるでしょう。いっぽう、計算機は疲れることを知りません。24時間、1年間、ずーっと動作することが可能です。ですから、テストインスタンスの生成は計算機向きの問題だと言えます。効率良く、つまりできるだけ早く、かつ「良い」テストインスタンスを作成する手法は自明ではなく、研究の余地があります。データベースのサイズはいまや巨大になりましたから、テストに合格したテストインスタンスをデータベースに格納し、まだ試していないテストインスタンスを新たにテストし続けるイテレーションが、テスト対象プログラムの問題を見つける可能性を高めます。

_ 拝啓、Software Design 2008 年 2 月号様

特集記事「Emacs マスターへの道」がよかったです。ありがとうございます。

Emacs のライブラリの紹介 p.142 - p.145 で、Flymake for Haskell が載っていました。脚注にですが。マイナーなのに、とりあげてくれてありがとう。著者のアリエルネットワーク(株)松山様のブログはいつも読んでいます。参考になる記事が多くて助かります。どうもどうも。

_ RSpec v.s. Unit::Test

Ruby 関西という勉強会で話したのですが、両者の本質は同じです。単に記述法が違うだけです。assert 派か should 派かという違いくらいしかありません。RSpec のほうが Ruby っぽくないという人もいるし、むしろ Ruby っぽいという人もいます。Ruby っぽいとかいうのは数学じゃないから僕は嫌いだ。

ただ、実行結果の出力の可視化が違うと思います。色がついたりとか。Rake, RCov, AutoTest なんかと組み合わせて使うと、可能性がひろがります。

デメリットとしては、RSpec の記法を覚えるのがすげえ面倒だということです。こんなの覚える暇があったら、違うことをするというあなたも正しいです。

るびまのRSpec紹介記事が秀逸です。私のスライドは水着だったから見せない。

僕が期待していたのは、RSpec がずっと命題論理に近い記述なので、論理学方面の技術が導入されてよりよいテスト環境になるのではないかな、と。でも数年たっても一向にその気配を見せないので、おそらくそういうコミュニティなのでしょうね。

_ それはそうと

しばらくすると、' ' 才です。とうとう、制御文字エリアからの脱出です。printable になるのです。おめでとう!おめでとう俺!printable なのに、まだ見えていませんが。今年は存在感が臼井君ですが、来年は '!' な歳、4年後には '$' な歳になっているといいな、と思います。man ascii.

今年の目標は、経験値を Charisma の上昇に使うことです。Gary Gygax の訃報を聞いて、D&D の能力値を「なぜ」あの 6 種類にしたのかということを改めて思い直しました。Charisma 以外の値は、ダイスの目に加算される直接的な効果を表しますが、Charisma は主にマスターとの口頭でのやりとりで用いられます。つまり、マスターの解釈がかなり入るんだな。

クラスとして Magic User を選んだので、今までは Lv. の上昇と Inteligence にのみ目が行ってましたが、ここ数年(特に留学時代) Charisma が為し得る魔術を目の当たりにしました。あれは黒魔術でも白魔術でもない魔術だった。The world の隠れた力を使うために Charisma 値が影響しているなんてルールは聞いてなかったぞ。

いけがみをサポートしたい!と他人に思わせるような人間になることを目指します。かわいがられたいです。かわいそがられたいのかも。どっちでもいいや。


2008-03-14 紫花菜は智慧の泉 [長年日記]

_ Purely testing

Type-driven testing in Haskell (Simon Peyton Jones)より。

Simon の主張はいつもすばらしいのだけど、この発表に関しては Summary に首をかしげる人もいるかもしれない(わたしもその一人):

  1. Over the next 10 years, the software battleground will be the control of effects
  2. To succeed, we must shift programming perspective from imperative-by-default to functional-by-default
  3. A concrete example: testing
    • Functional programs are far easier to test
    • A functional language is a fantastic test generation tool

Simon Peyton Jones, "Purely testing", 2008 スライド 2 枚目より抜粋

うむ。ほとんどの点には同意する。私が現時点で Simon と違う意見を持っているのは次の点:

  • 手続き型プログラミング言語 ( C など) を使う場面は、今後もおそらく続く ( LISP マシンは普及しなかった)
  • fantastic test generation tools は関数型言語以外の言語で書けないのか?書けるだろ。

実際、 Simon が褒めている Haskell の QuickCheck (a fantastic test generation tool) は、 Ruby にすんなり移植できた。もちろん、 Ruby は純粋でないので、Ruby でのテストは純粋でないが、「純粋」であることが重要だとは思わない。Haskell だって IO みたいな「純粋もどき」を使ったプログラムをテストしたいときに「純粋な」テストは意味をなさない。

私のもうひとつの個人的な意見は、「テスト対象のプログラミング言語には、fantastic test generation tools があるべき」というものである。あ、ここで勘違いしてほしくないんだけど、"fantastic" については Simon と同じ感覚を持っています。従来のテストライブラリ(UnitTest, Test Coverage, あらゆるテストの視覚化(表とか), 下流 CASE ツール)は、fantastic じゃない。現場の人ならわかってると思うけど、致命的なバグ、見付からないでしょ?そんなツール使ってもさ。

どんなプログラミング言語で書かれたプログラムも、Haskell でテストできるのは間違いない。しかし、そいつは次のような弱点を持つ:

  1. Haskell や Haskell FFI を使う方法の弱点:型が合うとは限らない、bridge をうまく作れない、Haskell がとろいせいで microsecond 割込みみたいなバグは見つけられない
  2. Haskell で対象プログラムをモデル化する方法の弱点:モデルが現実の実装を模倣しているとは限らない、見付かった反例が本当のバグとは限らない

Simon のスライド 43 ページには、「John が 2 番目のやり方でうまくいってるぜ」って言ってるけど、ほんとかなあ。や、John はスーパーハカーな上に頭がすんばらしく良いので、何か秘密があるのかもしらんけど。こいつについては、John に個人的に聞いてみる。

さて、これら以外にも Haskell でテストする方法があるのかもしれない。でも、僕の仮説「テストライブラリに『純粋』は必ずしも必要ない」ことが正しいなら、テスト対象のプログラミング言語で書かれた fantastic test generation tools が必要とされているはずだ。

具体例を挙げよう。Web application や、GUI 。みなさん、テスト書いてますか。テストってなんですか。テストにかかる時間、ものすごくかかりませんか。いちいち httpd とか database とか、たくさんのボタンのついた window をひとつひとつのテストの度に生成して、テストしてんの?

スーパーマリオクラブの従業員の皆様には本当に頭が下がるばかりです。時給 1,000 円ですか...

そういう事態を改善したくて Ruby でプロトタイプ実装してみたわけだけど、反応はほとんどなかった。Ruby はやっぱりそういうコミュニティなんだ...某氏曰く、「Ruby 使う人は Random Testing について知らないんじゃないですか」そう、LLer は指を加えて待ってる。便利なフレームワーク、便利なツール、便利な何か、そういうのを誰かが作ってくれるのを待ってる。どのように作るのか、何が欲しいのか、そういうのを考えているのは一握りのメンバーだけ。他の奴らは IT なんとかとか、はてななんとかで取り上げられて初めて飛びつくんだ。で、君達はプログラマなんですか、あっそう。

これは僕の失敗だ。ニーズのあるところにシーズを撒かなければならない。リサーチ不足でした。すみません。俺の時間は無駄に過ぎたが、十分いい勉強になった。さようなら。

じゃあどういうコミュニティは Random Testing について興味を持ってくれるんですかね。と自問したのだが、マイナーな言語で何かこさえてもマイナーなだけさね。 Java は Ruby とほとんど同じテクニックで実装できる(むしろ記述が長くなる分面倒だ)から、僕自身つまんない。Python に行っちゃおうかなーとも思うがそれはなんて Zed Shaw (Python の PeckCheck 0.1の実装がサイテーというのは John と話した)。となると、今、思いつく候補は C か JavaScript か Flex3 か(世間知らず)。

わーった。 C にしちゃる。ちょっとしたアイデアがあるので、うまくいく可能性がある。もっとも難問はいくつもある:ポインタ、型キャスト、void、union、致命的エラー (bus error, stack overflow, etc) を拾えない、など。うげえ、全てを救うのは無理っぽい。挑戦しがいのある課題。ともかく "a lightweight tool for random testing of imperative programming languages" が僕には必要だ。今ならまだ引き返せるので、深みに嵌まる前によーくあっためとかないと、まーた二の舞である…

ちなみに、Simon は Haskell 以外では Erlang, F#, Ocaml, Scala, Scheme, C# あたりが今後クルんじゃないの、と言っている。そうだろうね。でも、あいにく、へそ曲がりなので。そいつらに fantastic な機能を付け加えるのは誰でもできるんだよ。


出現予定(召喚方法 ikegami@madscientist.jp):

RSS feed を再開しました。RSS の思想を尊重するために全文配信はしません、あしからず。