Rust スマート コントラクト開発に関する BlockSec の前回の記事では、コントラクト StatusMessage のコントラクト ステータスを定義する方法を紹介し、コントラクトにさまざまなメソッドを実装しました。今回も引き続き契約書をベースに単体テストケースの書き方を詳しく紹介し、契約書をローカルでテストしていきます。1. 単体テスト環境を準備する
1 #[cfg(not(target_arch = "wasm32"))]
2 #[cfg(test)]
3 mod tests {
4 use super::*;
5 use near_sdk::MockedBlockchain;
6 use near_sdk::{testing_env, VMContext};
7
8 ...
9}
単体テストを作成するには、まず次のコードを src/lib.rs に追加して単体テストの環境をセットアップする必要があります。"wasm32"))]。
上記のコードの 1 ~ 3 行目では、StatusMessage の testing サブモジュールを追加し (mod キーワードを使用して新しいモジュールを宣言)、 module のコード スニペットの前に cfg 属性マクロ #[cfg(test)] をマークしました。また、Rust のネイティブ単体テストでは Wasm コードを取得する必要がないため、テスト モジュールは Rust のコンパイル条件 #[cfg(not(target_arch =
コードの 4 ~ 6 行目では、コントラクト テスト環境の関連する依存関係を、near_sdk (NEAR のソフトウェア開発キット) からインポートします。具体的には、コードの各行での use キーワードの使用法は、他の依存モジュールをインポートするときに Python 言語コードで使用されるインポートと似ています。 use 宣言は、他のパスと同義の 1 つ以上のローカル名バインディングを作成します。つまり、 use キーワードは、モジュール項目を参照するために必要なパスを宣言するためによく使用され、これらの宣言は通常、Rust モジュールの先頭に表示されます。コードブロック。
4 行目では、super キーワードを使用して現在のモジュールから親モジュールの StatusMessage にアクセスでき、以前に StatusMessage コントラクトに対して定義したメソッド関数 set_status や get_status など、親モジュールで定義された関数やメソッドにアクセスできるようになります。 5 行目では use キーワードを使用して、nearsdk が提供するモック ブロックチェーン MockedBlockchain サポート モジュールを参照します。これはスマート コントラクトのテストに使用できます。 6行目では、nearsdkからのコントラクトテスト実行環境と、テスト環境のコンテキスト情報形式のサポートを紹介しています。
1 fn get_default_context(view_call: bool) -> VMContext {
2 VMContext {
3 current_account_id: "alice_near".to_string(),
4 signer_account_id: "bob_near".to_string(),
5 signer_account_pk: vec!,
6 predecessor_account_id: "carol_near".to_string(),
7 input: vec!,
8 block_index: 0,
9 block_timestamp: 0,
10 account_balance: 0,
11 account_locked_balance: 0,
12 storage_usage: 0,
13 attached_deposit: 0,
14 prepaid_gas: 10u64.pow(18),
15 random_seed: vec!,
16 is_view: view_call,
17 output_data_receivers: vec!,
18 epoch_height: 0,
19 }
20 }
NEAR スマート コントラクトの単体テストをサポートするために必要な外部依存関係モジュールをインポートした後、テスト環境で必要なコンテキスト情報を構成して返すために、テスト モジュールで次の関数 get_context() を定義する必要もあります: VMContext。
VMContext は、複数のシミュレーション、契約ユーザー アカウント情報、およびブロックの高さ、ブロック タイムスタンプ、契約ストレージの使用量などを含むブロックチェーンの最下層に関連するコンテキスト構成情報を設定します。
以下ではまず、VMContext のいくつかの主要な属性構成について説明します。
current_account_id: 現在の契約を実行しているアカウント。 Signer_account_id: 現在のコントラクト関数呼び出しの実行をトリガーするトランザクション署名者。すべてのコントラクト呼び出しはトランザクションの結果であり、トランザクションはアクセス キー (signer_account_id) を使用してアカウントによって署名されます。 Signer_account_pk: トランザクション署名者が使用するアクセス キー公開キー (Public Key)。先行者_アカウント_id: コントラクトの実行がクロスコントラクト呼び出しまたはコールバックである場合、この属性は呼び出しの開始者アカウントを参照します。単一のコントラクト内部関数呼び出しを行う場合、この値はsigner_account_idと一致します。 prepaid_gas: ブロックチェーン上で契約を実行する際、ユーザーは一定の取引実行手数料(ガス料金)を支払う必要がある機能があります。ここでのprepaid_gasは、現在のトランザクションコントラクト関数が呼び出されたときに差し引かれるGasの最大値を設定し、現在のコントラクト呼び出しに追加されます。 is_view: パラメータ is_view (型は bool) は、コントラクト関数の呼び出しによってコントラクトの状態データを変更できるかどうかを設定できます。値が true の場合、コントラクト関数の実行時にコントラクトのステータス データは読み取り専用になります。逆に、値が false の場合、コントラクトの実行環境ではコントラクト データの変更が許可されます。 VMContext の残りの属性の内容と使用法については、後続の記事で詳しく説明します。
near_sdk::env::current_account_id()
near_sdk::env::predecessor_account_id()
near_sdk::env::signer_account_pk()
near_sdk::env::input()
near_sdk::env::predecessor_account_id()
NEAR コントラクトを実行する際、プログラムは NEAR SDK が提供するいくつかの関連 API と連携して、設定されたコンテキスト情報を読み取ることができます。例えば:
上記の API はすべて、コンテキスト固有のプロパティの値を返します。これらの API は、前述の use ステートメントを使用してインポートできます。
get_context() 関数を定義した後、単体テストのコンテンツをテスト モジュールに 1 つずつ記述できます。
2. 単体テスト 1
1 #[test]
2 fn set_get_message() {
3 let context = get_default_context(false);
4 testing_env!(context);
5 let mut contract = StatusMessage::default();
6 contract.set_status("hello".to_string());
7 assert_eq!(
8 "hello".to_string(),
9 contract.get_status("bob_near".to_string()).unwrap()
10 );
11 }
単体テスト 1 のコード スニペットは次のとおりです。
次に、テスト ケースの具体的な作成方法について説明します。
上記のコード スニペットの 1 行目で、単体テスト関数を #[test] マクロでマークし、これが単体テストの開始点であることを示しています。 2 行目の直後に単体テスト関数 set_get_message() の宣言があります。
コードの 3 行目から 10 行目は単体テスト関数内のメイン テスト ロジックで、コード実装は最初に以前に定義された get_context を呼び出して、テスト環境で使用されるコンテキスト コンテキストを初期化します。さらに、この単体テストではコントラクトの状態データにデータを書き込む必要があるため、get_context のパラメーターを設定し、前述の VMContext の is_view 属性を false に設定する必要があることに注意してください。そうしないとパニックが発生します。単体テスト内でトリガーされます。テストは失敗しました。
適切なコントラクト実行コンテキストを設定した後、コードの 4 行目では、コンテキスト VMContext を使用して testing_env! マクロを使用し、スマート コントラクト インタラクション用の MockedBlockchain インスタンスを初期化します。コードの 5 行目では、親モジュールで定義された StatusMessage::default() を呼び出して、初期化されたコントラクト オブジェクト コントラクトを生成します。"Hello"後続のコードでは、テストは最初に親モジュール StatusMessage によって定義された set_status メソッドを呼び出して、文字列を契約ステータス データに保存します。"assertion failed"。次に、get_status を使用して契約状況データからデータを読み取り、予想される内容と比較します。コンテンツが互いに一致する場合はこの単体テストに合格し、一致しない場合はこのテスト スレッドを起動します。
パニックの一種。
単体テストでassertを使って検証する場合の書き方は以下の通りです。
assert_eq!(left,assert!(expression) マクロはブール値をチェックし、expression 式によって参照される内容が true の場合にのみテストに合格します。
assert_ne!(left,右) マクロは、それらが等しいかどうかをチェックするためによく使用され、左と右の式によって参照される内容が一貫している場合にのみチェックに合格します。
右) マクロは、それらが異なるかどうかをチェックするためによく使用され、左と右の式によって参照される内容が異なる場合にのみチェックに合格します。
3.単体テスト2
1 #[test]
2 fn get_nonexistent_message() {
3 let context = get_default_context(true);
4 testing_env!(context);
5 let contract = StatusMessage::default();
6 assert_eq!(None, contract.get_status("francis.near".to_string()));
7 }
単体テスト 2 のコード スニペットは次のとおりです。
6 行目のテストでは、assert_eq の右側の式は、コントラクト メソッド get_status を使用して、StatusMessage コントラクト ユーザー francis.near に対応するメッセージ情報をコントラクト ステータス データからクエリしようとします。ただし、コードの5行目はコントラクト全体の状態を初期化しているだけなので、この時点のコントラクトデータは全体としては空であるため、戻り値はNoneとなります。最後に、結果が期待どおりであるため、アサーションは正しく、単体テストに合格できます。
4. テストケースを実行する
[dependencies]
near-sdk = "3.1.0"
上記の単体テストを作成した後、StatusMessage Rust プロジェクトのコントラクトの Cargo.toml ファイルを構成する必要があります。つまり、ファイルの [dependency] セクションに Near-sdk への依存関係を追加します (バージョン番号は3.1.0)。
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
use near_sdk::collections::LookupMap;
use near_sdk::{env, near_bindgen};
同時に、src/lib.rs ファイルの先頭にある Near_sdk からこれらのモジュールまたはパッケージをインポートする必要もあります。
$ cargo test --package status-message
コントラクト プロジェクトの依存関係を構成した後、cargo を使用してすべての単体テスト ケースを実行できます。具体的なコマンドは以下のとおりです。
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in0.00s
テストは特定のテスト結果を返します。
$ cargo test --package status-message set_get_message
同様に、個々のテストの結果を取得できます。
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in0.00s
この問題の概要とプレビュー
この問題の概要とプレビュー