「TAURI」と「Rust」の「テスト」機能を試してみよう
はじめに
今回は「Rust」の「テスト」機能を解説します。テストとはプログラムが正常に動作しているか検証するための機能のことです。テストプログラム実行時の計算結果の値が正しいかどうかを「assert_eq!」「assert_ne!」「assert!」「panic!」の各マクロを使って検証します。
また、本連載は「TAURI」がテーマでもあるので、TAURIを使う際のRustについてもテストします。TAURIでのテストの際はフロントエンドの「HTML5+JavaScript+CSS」はほとんど関係しません。
Rustでテストをするためのプロジェクト
まず、TAURIではなくRustのみのプロジェクトを作成します。追加で必要なクレートはありません。
ライブラリ用のプロジェクトの作成
第1回のRustの設定が済んでいる前提で話を進めていきます。適当なフォルダをカレントディレクトリにして、次のコマンドを実行して「rust_test」などという名前でプロジェクトを新規作成します。「--lib」オプションはライブラリ用のプロジェクトを作成します。それから作成した「rust_test」フォルダをカレントディレクトリにします。
・ライブラリ用のRustプロジェクトの作成コマンド$ cargo new rust_test --lib
テンプレートプロジェクトのテスト
まずは作成されたプロジェクトを次のコマンドを実行してテストしてみます。今までのように「cargo」コマンドで「run」や「build」を実行して実行ファイルを作るのではなく、「test」を実行してテストします。
テンプレートのソースコードの内容は「add」関数で2つの引数の値「2」と「2」を加算した結果を返し、その戻り値が「4」と等しいか調べるだけの単純なものです。
・Rustのテストを実行$ cargo test
すると、図1のような文がターミナルに表示されます。各文の意味は下記の通りです。
- test result: ok.
→テストの結果はOKでした - 1 passed;
→1個テストを通過しました - 0 failed;
→0個テストが失敗しました - 0 ignored;
→0個テストが無視されました - 0 measured;
→0個テストでパフォーマンスを調べました(nightly版のRustのみの機能) - 0 filtered out;
→0個テストでフィルターがかけられました
テストを実行してみる
テストにはassert_eq!、assert_ne!、assert!、panic!の4つのマクロのいずれか、または全部を使います。ここでのサンプルコードでは、分かりやすいように最低限の例だけコーディングしています。ここで、簡単に各マクロについて解説しておきます。
- assert_eq!マクロ
「assert」とは「主張する」という意味で「eq」は「equal」の略と思われます。文字通り主張が「イコール(等しい)」かを調べるテストをします。 - assert_ne!マクロ
「ne」は「not equal」の略と思われます。文字通り主張が「ノット イコール(等しくない)」かを調べるテストをします。 - assert!マクロ
主張の真偽をテストします。「true」ならテストに成功し、「false」ならテストに失敗します。 - panic!マクロ
文字通り「パニック(慌てる)」することで、常にテストに失敗します。オリジナルのテストを作るときなど、失敗を表す場合に使います。
assert_eq! マクロ
デフォルトのプロジェクトは2つの引数の値が等しいか調べるassert_eq!マクロが成功した例でした。今度は次のサンプルコードのようにassert_eq!マクロが失敗します。
次のテストを実行すると「tests::it_works」が「test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s」と表示されます。「test result: FAILED.」でテスト結果が失敗を表しています(図2)。
「#[cfg(test)]」の次行からのモジュールがテスト対象になります。「#[test]」の次行からの関数を呼び出さなくてもテストされます。ここでは最も単純な等不等を調べているだけですが、皆さんはご自身のコードで複雑な計算をテストしてみてください。
・「src」→「main.rs」ファイルの「assert_eq!」マクロのサンプルコード//testsモジュールをテスト対象に #[cfg(test)] mod tests { //it_works関数をテスト #[test] fn it_works() { //等しいとテスト成功 assert_eq!(1+1, 3); } }
【サンプルコードの解説】
#[cfg(test)]の「cfg」には環境に応じたコンパイルを指定し、「()」内が「アトリビュート(属性)」です。ここでは「test」属性でコンパイルを指定します。
「mod」文はモジュール宣言です。
#[test]の次行からが「test」関数であることを表しています。
testのit_works関数はテストを実行する際に呼ばれ、assert_eq!マクロで1つ目の引数と2つ目の引数が等しければテスト成功です。
assert_ne! マクロ
次は、2つの引数の値が等しくないことを調べるassert_ne!マクロの例です。次のサンプルコードのようにassert_ne!マクロの2つの引数が等しくない場合に成功します。
次のテストを実行すると「tests::it_works」が「test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s」と表示されます。「test result: ok.」でテスト結果がOKでした。
・「src」→「main.rs」ファイルの「assert_ne!」マクロのサンプルコード#[cfg(test)] mod tests { #[test] fn it_works() { //等しくないとテスト成功 assert_ne!(1+1, 3); } }-----
【サンプルコードの解説】
testのit_works関数はテストを実行する際に呼ばれ、assert_ne!マクロで1つ目の引数と2つ目の引数が等しくなければテスト成功です。
assert! マクロ
続いて引数の値がtrueかfalseか調べるassert!マクロの例です。次のサンプルコードのようにassert!マクロの引数がtrueの場合に成功します。次のテストを実行すると「tests::it_works」が「test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s」と表示されます。「test result: ok.」でテスト結果がOKでした。
・「src」→「main.rs」ファイルの「assert!」マクロのサンプルコード#[cfg(test)] mod tests { #[test] fn it_works() { //trueなら成功、falseなら失敗 assert!(1+1 == 2); } }
【サンプルコードの解説】
testのit_works関数はテストを実行する際に呼ばれ、assert!マクロで1つ目の引数が「true」ならテスト成功です。
panic! マクロ
最後は常にテストが失敗するpanic!マクロの例です。次のサンプルコードのようにpanic!マクロの引数の「動物名がありません!」がターミナルにエラー内容として表示されます。新たに「use super::*;」が出てきますが、これによりテストするモジュール外で定義したものも「tests」モジュール内で全て使えるようにします。
次のテストを実行すると「tests::no_name」が「test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s」と表示されます。「test result: FAILED.」でテスト結果が失敗でした。
・「src」→「main.rs」ファイルで「panic!」マクロのサンプルコード//動物の構造体 struct Animal { name: String, } //動物の構造体のメソッド impl Animal { fn new(name: String) -> Self { Animal { name: name, } } } #[cfg(test)] mod tests { //モジュール外の定義を使えるように use super::*; //動物名があるかをテスト #[test] fn no_name() { let instance = Animal::new(String::from("")); if instance.name == "" { panic!("動物名がありません!"); } } }
【サンプルコードの解説】
「name」プロパティを持った「Animal」構造体を宣言します。
Animal構造体のコンストラクタを「new」メソッドで宣言します。
testsモジュールをtest属性にします。
「use」文で全てのモジュール外の定義を使えるようにします。
テスト関数として宣言した「no_name」関数はテストを実行する際に呼ばれ、Animal構造体のインスタンスのname文字列が""(空)ならpanic!マクロで1つ目の引数の"動物名がありません!"文字列がエラーとして表示されます。
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- 「TAURI」の基礎知識を押さえ、簡単なTAURIアプリ開発を体験してみよう
- 「TAURI」と「Rust」の「Option型」と「Result型」を使いこなそう
- 「TAURI」で「ピアノ音楽」アプリを作ろう
- 「TAURI」で「簡易RSSリーダー」を開発してみよう
- 「TAURI」でデータベースを使ってみよう
- 「Ace」を使って「TAURI」で「テキストエディタ」アプリを作ろう
- 「TAURI」で「画像ビューア」のサンプルアプリを作ろう
- 「TAURI」でExcelのデータを読み書きしてWebページに表示してみよう
- アサーションの使い方
- 「TAURI」をはじめる前に -「Rust」の基礎と開発環境の構築