Rustについて基本からしっかり学んでいく本連載。第14回は、Rustの備える自動テスト機能である単体テストと統合テスト、ドックテストについて。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
Rustは、標準で自動テスト機能をサポートしています。自動テスト機能とは、文字通りプログラムの正当性を自動でテストする機能で、バグのない安全なプログラムの開発には必須です。テストを自動化することで、コードを改変した際の動作検証の手間も最低限に抑えられます。
Rustの備える自動テスト機能には、大きく分けて以下の3つがあります。
単体テストは、ユニットテストとも呼ばれ、テストの基本です。関数やメソッド単位で実行し、与えた引数に対して期待する値が返るかなど、基本的な動作を検証するために用いられます。
結合テストは、複数の関数やメソッド、モジュールやクレートにまたがったテストです。単体テストはあくまでも関数、メソッドの単体での動作をテストするものですが、それらが組み合わさった機能としての挙動をテストするのが結合テストです。
ドックテストのドックとは、ドキュメントのことです。ソースファイルのドキュメンテーションコメントに含まれるコードをテストするために用いられます。ドキュメンテーションコメントにはコード例が記載されることが多いですが、それをコメントとしたままでテストできるので便利です。
テストには、ほかにシステムテスト(ユーザーの操作などの外部入力に対して期待する結果が得られるかどうかのテスト)などがありますが、Rustでは単体テスト、結合テストを中心にサポートします。今回は、この2つにドックテストを加えて紹介していきます。なお、今回のサンプルはtestingsパッケージとして作成していきます。
適切なテストのためには、テストプロセスの設計から始まる作業の策定やテスト項目、テストケースの作成が必要となってきます。また、仕様書を基にするブラックボックステスト、内部設計を基にするホワイトボックステストの分類もあります。それらをここで全て紹介することはできないため、ごくシンプルなテストケースに限定し、サンプルを紹介していくことにします。
単体テストの対象とする関数やメソッドは、通常はライブラリクレートとして独立させておきます。ここでは、ライブラリクレートを1個作成し、その中に関数を1個作成して、その関数を単体テストする過程を通じて、単体テストを学んでいきましょう。
ライブラリクレートの作成については、これまで何度か触れました。cargo newコマンドで--libオプションを付けてパッケージを作成すると、ライブラリクレートが作成されます。
% cargo new --lib testings Created library `testings` package
以下は、作成されたライブラリクレートです。
#[cfg(test)] (1) mod tests { (2) #[test] (3) fn it_works() { (4) assert_eq!(2 + 2, 4); (5) } }
これは自動生成されたライブラリクレートの中身ですが、単体テストのために必要な特徴的な構文がたくさん詰まっています。自分でテストのためのコードを書くためにも必要なものですから、しっかりと見ておきましょう。
(1)は、test構成でのみコンパイルされるコードの指定です。他の構成(debug構成、release構成などテストコードを必要としない構成)においてテストのためのコードがコンパイルされ、結果としてのバイナリに含まれてしまう無駄を省くための注釈(アノテーション)です。
(2)は、テストのコードのためのモジュールの宣言です。このモジュール名は、常にtestsとなることに注意してください。
(3)は、続く関数の宣言がテストメソッドであることを示す注釈です。コンパイラは、この注釈が付いた関数をテスト関数として認識し、実行します。それぞれのテスト関数で共有するサブ関数など、テスト関数として実行しない関数にはこの注釈は不要です。
(4)は、テスト関数の宣言です。名前は自由で構いませんが、テストを実行するとこの名前で経過が出力されますから、テスト関数の目的が分かる名前を付けます。例えば、この場合はit_worksですから「正しく動く」ことになるでしょう。ここに、失敗するテストコードを書くのは意味的に不適切です。
(5)は、テスト関数の内容です。ここでは、assert_eq!マクロを呼び出して2つの引数の値が等しいことを判定しているだけですが、実際のテストでは対象の関数やメソッドを呼び出すコードを記述します。assert_eq!マクロをはじめとする、テスト関数で有用なマクロについては別途紹介します。
Copyright © ITmedia, Inc. All Rights Reserved.