自動テストを書く

1972年のエッセイ「謙虚なプログラマ」でエドガー・W・ダイクストラは以下のように述べています。 「プログラムのテストは、バグの存在を示すには非常に効率的な手法であるが、 バグの不在を示すには望み薄く不適切である」と。これは、できるだけテストを試みるべきではないということではありません。

プログラムの正当性は、どこまで自分のコードが意図していることをしているかなのです。 Rustは、プログラムの正当性に重きを置いて設計されていますが、 正当性は複雑で、単純に証明することはありません。Rustの型システムは、 この重荷の多くの部分を肩代わりしてくれますが、型システムはあらゆる種類の不当性を捕捉してはくれません。 ゆえに、Rustでは、言語内で自動化されたソフトウェアテストを書くことをサポートしているのです。

例として、渡された何かの数値に2を足すadd_twoという関数を書くとしましょう。 この関数のシグニチャは、引数に整数を取り、結果として整数を返します。 この関数を実装してコンパイルすると、コンパイラはこれまでに学んできた型チェックと借用チェックを全て行い、 例えば、Stringの値や無効な参照をこの関数に渡していないかなどを確かめるのです。 ところが、コンパイラはプログラマがまさしく意図したことを関数が実行しているかどうかは確かめられません。 つまり、そうですね、引数に10を足したり、50を引いたりするのではなく、引数に2を足していることです。 そんな時にテストは、必要になるのです。

例えば、add_two関数に3を渡した時に、戻り値は5であることをアサーションするようなテストを書くことができます。 コードに変更を加えた際にこれらのテストを走らせ、既存の正当な振る舞いが変わっていないことを確認できます。

テストは、複雑なスキルです: いいテストの書き方をあらゆる方面から講義することは1章だけではできないのですが、 Rustのテスト機構のメカニズムについて議論します。テストを書く際に利用可能になるアノテーションとマクロについて、 テストを実行するのに提供されているオプションと標準の動作、さらにテストをユニットテストや統合テストに体系化する方法について語ります。