Trong bài viết trước của BlockSec về phát triển hợp đồng thông minh Rust, chúng tôi đã giới thiệu cách xác định trạng thái hợp đồng cho StatusMessage hợp đồng và triển khai các phương pháp khác nhau cho hợp đồng. Trong số này, chúng tôi sẽ tiếp tục tường thuật dựa trên hợp đồng, giới thiệu chi tiết phương pháp viết các trường hợp kiểm tra đơn vị và kiểm tra hợp đồng tại địa phương.1. Chuẩn bị môi trường kiểm thử đơn vị
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}
Để viết unit test, đầu tiên chúng ta cần thêm đoạn mã sau vào src/lib.rs để thiết lập môi trường cho unit test:"wasm32"))]。
Trong các dòng 1-3 của đoạn mã trên, chúng tôi đã thêm mô-đun con kiểm tra cho StatusMessage (sử dụng từ khóa mod để khai báo mô-đun mới) và đánh dấu macro thuộc tính cfg #[cfg(test)] trước đoạn mã của mô-đun . Ngoài ra, do các bài kiểm tra đơn vị gốc của Rust không cần lấy mã Wasm, nên mô-đun kiểm tra có thể được định cấu hình với các điều kiện biên dịch Rust #[cfg(not(target_arch =
Các dòng 4-6 của mã nhập các phụ thuộc có liên quan của môi trường thử nghiệm hợp đồng từ near_sdk (bộ công cụ phát triển phần mềm của NEAR). Cụ thể, trong mỗi dòng mã, cách sử dụng từ khóa sử dụng tương tự như cách nhập được sử dụng bởi mã ngôn ngữ python khi nhập các mô-đun phụ thuộc khác. Khai báo sử dụng tạo ra một hoặc nhiều liên kết tên cục bộ đồng nghĩa với các đường dẫn khác, tức là từ khóa sử dụng thường được sử dụng để khai báo các đường dẫn cần thiết để tham chiếu đến một mục mô-đun và các khai báo này thường có thể xuất hiện ở đầu mô-đun Rust hoặc khối mã.
Trong dòng 4, từ khóa super có thể được sử dụng để truy cập StatusMessage mô-đun chính từ mô-đun hiện tại, cho phép truy cập vào các hàm và phương thức được xác định trong mô-đun chính, chẳng hạn như các hàm phương thức set_status và get_status mà chúng ta đã xác định cho hợp đồng StatusMessage trước đó. Dòng 5 sử dụng từ khóa sử dụng để chỉ mô-đun hỗ trợ chuỗi khối giả MockedBlockchain do nearsdk cung cấp, mô-đun này có thể được sử dụng để thử nghiệm hợp đồng thông minh. Dòng 6 giới thiệu môi trường thực hiện thử nghiệm hợp đồng từ nearsdk, cũng như hỗ trợ định dạng thông tin ngữ cảnh của môi trường thử nghiệm.
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 }
Sau khi nhập các mô-đun phụ thuộc bên ngoài cần thiết để hỗ trợ các thử nghiệm đơn vị hợp đồng thông minh NEAR, chúng tôi cũng cần xác định hàm get_context() sau trong mô-đun thử nghiệm để định cấu hình và trả về thông tin ngữ cảnh cần thiết trong môi trường thử nghiệm: VMContext.
VMContext đặt nhiều mô phỏng, thông tin tài khoản người dùng hợp đồng và thông tin cấu hình ngữ cảnh liên quan đến lớp dưới cùng của chuỗi khối bao gồm chiều cao khối, dấu thời gian khối, sử dụng bộ nhớ hợp đồng, v.v.
Phần đầu tiên sau đây giải thích một số cấu hình thuộc tính chính trong VMContext:
current_account_id: Tài khoản thực hiện hợp đồng hiện tại. signer_account_id: Người ký giao dịch kích hoạt thực hiện lệnh gọi hàm hợp đồng hiện tại. Tất cả các lệnh gọi hợp đồng là kết quả của một giao dịch và giao dịch được ký bởi một tài khoản bằng Khóa truy cập của nó, đó là signer_account_id. signer_account_pk: Khóa công khai Access Key (Public Key) do người ký giao dịch sử dụng. tiền nhiệm_tài khoản_id: Khi việc thực thi hợp đồng là một cuộc gọi hợp đồng chéo hoặc gọi lại, thuộc tính này đề cập đến tài khoản người khởi xướng cuộc gọi. Khi thực hiện một lệnh gọi hàm nội bộ hợp đồng, giá trị này sẽ nhất quán với signer_account_id. Prepaid_gas: Có một tính năng khi thực hiện hợp đồng trong blockchain, đó là người dùng cần trả một khoản phí thực hiện giao dịch nhất định (phí gas). Prepaid_gas ở đây đặt giá trị Gas tối đa có thể được khấu trừ khi chức năng hợp đồng giao dịch hiện tại được gọi và nó được thêm vào lệnh gọi hợp đồng hiện tại. is_view: Tham số is_view (loại là bool) có thể đặt xem lệnh gọi hàm hợp đồng có thể sửa đổi dữ liệu trạng thái của hợp đồng hay không. Nếu giá trị là true, dữ liệu trạng thái của hợp đồng ở chế độ chỉ đọc khi chức năng hợp đồng được thực thi. Ngược lại, nếu giá trị là sai, môi trường thực thi hợp đồng sẽ cho phép sửa đổi dữ liệu hợp đồng. Nội dung và cách sử dụng các thuộc tính còn lại trong VMContext sẽ được trình bày chi tiết trong các bài viết tiếp theo.
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()
Khi thực hiện hợp đồng NEAR, chương trình có thể hợp tác với một số API liên quan do SDK NEAR cung cấp để đọc thông tin ngữ cảnh đã đặt. Ví dụ:
Tất cả các API trên đều trả về giá trị của các thuộc tính theo ngữ cảnh cụ thể và các API này có thể được nhập bằng cách sử dụng câu lệnh sử dụng được mô tả trước đó.
Sau khi xác định hàm get_context(), chúng ta có thể viết từng nội dung kiểm tra đơn vị trong mô-đun kiểm tra.
2. Bài kiểm tra đơn vị 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 }
Đây là đoạn mã cho bài kiểm tra đơn vị 1:
Bây giờ chúng ta mô tả cách viết test case cụ thể:
Ở dòng 1 của đoạn mã trên, chúng tôi đã đánh dấu chức năng kiểm tra đơn vị bằng macro #[test], cho biết đây là điểm bắt đầu cho kiểm tra đơn vị. Ngay sau dòng 2 là phần khai báo hàm kiểm tra đơn vị set_get_message().
Các dòng 3-10 của mã là logic kiểm tra chính bên trong hàm kiểm tra đơn vị, trong đó việc triển khai mã trước tiên gọi get_context đã xác định trước đó để khởi tạo ngữ cảnh ngữ cảnh được sử dụng trong môi trường kiểm tra. Ngoài ra, điều đáng nói là vì bài kiểm tra đơn vị này cần ghi dữ liệu vào dữ liệu trạng thái của hợp đồng, nên cần phải đặt tham số cho get_context và đặt thuộc tính is_view trong VMContext được đề cập ở trên thành false, nếu không sẽ hoảng loạn được kích hoạt bên trong bài kiểm tra đơn vị. Bài kiểm tra không thành công.
Sau khi đặt ngữ cảnh thực thi hợp đồng hợp lý, dòng 4 của mã sẽ sử dụng ngữ cảnh VMContext để sử dụng macro testing_env! nhằm khởi tạo một phiên bản MocedBlockchain cho tương tác hợp đồng thông minh. Dòng 5 của mã sẽ gọi StatusMessage::default() được xác định trong mô-đun chính để tạo hợp đồng đối tượng hợp đồng đã khởi tạo."Hello"Trong mã tiếp theo, trước tiên, thử nghiệm sẽ gọi phương thức set_status được xác định bởi mô-đun cha StatusMessage để lưu chuỗi trong dữ liệu trạng thái hợp đồng"assertion failed". Sau đó, sử dụng get_status để đọc đoạn dữ liệu từ dữ liệu trạng thái hợp đồng và so sánh nó với nội dung dự kiến. Vượt qua bài kiểm tra đơn vị này nếu nội dung khớp với nhau, kích hoạt chuỗi kiểm tra này nếu chúng không khớp
kiểu hoảng loạn.
Cách viết sử dụng assert để verify trong unit test như sau:
assert_eq!(left,Macro khẳng định!(biểu thức) có thể kiểm tra giá trị boolean và vượt qua kiểm tra khi và chỉ khi nội dung được tham chiếu bởi biểu thức biểu thức là đúng;
assert_ne!(left,phải) macro thường được sử dụng để kiểm tra xem chúng có bằng nhau hay không và vượt qua kiểm tra nếu và chỉ khi nội dung được tham chiếu bởi các biểu thức bên trái và bên phải là nhất quán;
phải) macro thường được sử dụng để kiểm tra xem chúng có khác nhau hay không và vượt qua kiểm tra nếu và chỉ khi nội dung được tham chiếu bởi các biểu thức bên trái và bên phải là khác nhau;
3. Bài kiểm tra đơn vị 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 }
Đây là đoạn mã cho bài kiểm tra đơn vị 2:
Trong thử nghiệm ở dòng 6, biểu thức ở bên phải của assert_eq sử dụng phương thức hợp đồng get_status để thử truy vấn thông tin thông báo tương ứng với người dùng hợp đồng StatusMessage francis.near từ dữ liệu trạng thái hợp đồng. Tuy nhiên, vì dòng 5 của mã chỉ khởi tạo trạng thái của toàn bộ hợp đồng, nên toàn bộ dữ liệu hợp đồng tại thời điểm này là trống, vì vậy giá trị trả về của nó sẽ là Không có. Cuối cùng, vì kết quả đúng như mong đợi, khẳng định là chính xác và bài kiểm tra đơn vị có thể vượt qua.
4. Thực hiện test case
[dependencies]
near-sdk = "3.1.0"
Sau khi viết các bài kiểm tra đơn vị ở trên, chúng tôi cũng cần định cấu hình tệp Cargo.toml của hợp đồng trong dự án StatusMessage Rust, nghĩa là thêm phần phụ thuộc vào near-sdk trong phần [phụ thuộc] của tệp (số phiên bản là 3.1.0).
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
use near_sdk::collections::LookupMap;
use near_sdk::{env, near_bindgen};
Đồng thời, chúng ta cũng cần nhập các mô-đun hoặc gói này từ near_sdk ở đầu tệp src/lib.rs:
$ cargo test --package status-message
Sau khi định cấu hình các phụ thuộc của dự án hợp đồng, chúng tôi có thể sử dụng hàng hóa để thực hiện tất cả các trường hợp thử nghiệm đơn vị. Các lệnh cụ thể như sau:
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in0.00s
Bài kiểm tra sẽ trả về kết quả kiểm tra cụ thể:
$ cargo test --package status-message set_get_message
Tương tự, chúng ta có thể thu được kết quả của các bài kiểm tra riêng lẻ:
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in0.00s
Tóm tắt và xem trước vấn đề này
Tóm tắt và xem trước vấn đề này