ในบทความ BlockSec ก่อนหน้าเกี่ยวกับการพัฒนาสัญญาอัจฉริยะของ Rust เราได้แนะนำวิธีกำหนดสถานะสัญญาสำหรับ StatusMessage ของสัญญา และใช้วิธีการต่างๆ สำหรับสัญญา ในฉบับนี้ เราจะยังคงบรรยายตามสัญญา แนะนำรายละเอียดวิธีการเขียน unit test case และทดสอบสัญญาในพื้นที่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 (โดยใช้คำหลัก mod เพื่อประกาศโมดูลใหม่) และทำเครื่องหมายมาโครแอตทริบิวต์ cfg #[cfg(test)] ก่อนข้อมูลโค้ดของโมดูล นอกจากนี้ เนื่องจากการทดสอบหน่วยดั้งเดิมของ Rust ไม่จำเป็นต้องรับโค้ด Wasm โมดูลทดสอบจึงสามารถกำหนดค่าด้วยเงื่อนไขการรวบรวม Rust #[cfg(not(target_arch =
บรรทัดที่ 4-6 ของโค้ดนำเข้าการอ้างอิงที่เกี่ยวข้องของสภาพแวดล้อมการทดสอบสัญญาจาก near_sdk (ชุดพัฒนาซอฟต์แวร์ของ NEAR) โดยเฉพาะอย่างยิ่ง ในแต่ละบรรทัดของโค้ด การใช้คีย์เวิร์ด use จะคล้ายกับการนำเข้าที่ใช้โดยโค้ดภาษา python เมื่อนำเข้าโมดูลที่ต้องพึ่งพาอื่นๆ การประกาศใช้สร้างการเชื่อมโยงชื่อท้องถิ่นอย่างน้อยหนึ่งชื่อที่ตรงกันกับพาธอื่นๆ เช่น คีย์เวิร์ด use มักจะใช้เพื่อประกาศพาธที่จำเป็นในการอ้างถึงรายการโมดูล และโดยปกติแล้วการประกาศเหล่านี้อาจปรากฏที่ด้านบนของโมดูล Rust หรือ รหัสบล็อก
ในบรรทัดที่ 4 สามารถใช้คำสำคัญ super เพื่อเข้าถึงโมดูลหลัก StatusMessage จากโมดูลปัจจุบัน ทำให้สามารถเข้าถึงฟังก์ชันและวิธีการที่กำหนดไว้ในโมดูลหลัก เช่น ฟังก์ชันเมธอด set_status และ get_status ที่เรากำหนดไว้สำหรับสัญญา StatusMessage ก่อนหน้านี้ บรรทัดที่ 5 ใช้คำหลัก use เพื่ออ้างถึงโมดูลสนับสนุนจำลอง blockchain MockedBlockchain ที่จัดทำโดย nearsdk ซึ่งสามารถใช้สำหรับการทดสอบสัญญาอัจฉริยะ บรรทัดที่ 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: คีย์สาธารณะของคีย์การเข้าถึง (คีย์สาธารณะ) ที่ใช้โดยผู้ลงนามธุรกรรม predecessor_account_id: เมื่อการดำเนินการตามสัญญาเป็นการเรียกข้ามสัญญาหรือการโทรกลับ คุณลักษณะนี้จะอ้างถึงบัญชีผู้ริเริ่มของการโทร เมื่อทำการเรียกใช้ฟังก์ชันภายในของสัญญาเดียว ค่านี้จะสอดคล้องกับ signer_account_id prepaid_gas: มีคุณสมบัติในการดำเนินการตามสัญญาใน blockchain นั่นคือผู้ใช้ต้องจ่ายค่าธรรมเนียมการทำธุรกรรมบางอย่าง (ค่าน้ำมัน) prepaid_gas ที่นี่ตั้งค่าสูงสุดของ Gas ที่สามารถหักได้เมื่อมีการเรียกใช้ฟังก์ชันสัญญาธุรกรรมปัจจุบัน และจะถูกเพิ่มในการเรียกสัญญาปัจจุบัน is_view: พารามิเตอร์ is_view (ประเภทคือบูล) สามารถตั้งค่าได้ว่าการเรียกใช้ฟังก์ชันสัญญาสามารถแก้ไขข้อมูลสถานะของสัญญาได้หรือไม่ หากค่าเป็นจริง ข้อมูลสถานะของสัญญาจะเป็นแบบอ่านอย่างเดียวเมื่อดำเนินการฟังก์ชันสัญญา ในทางกลับกัน หากค่าเป็นเท็จ สภาพแวดล้อมการดำเนินการของสัญญาจะอนุญาตให้แก้ไขข้อมูลสัญญาได้ เนื้อหาและการใช้แอตทริบิวต์ที่เหลือใน 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 โปรแกรมสามารถทำงานร่วมกับ API ที่เกี่ยวข้องบางตัวที่จัดเตรียมโดย NEAR SDK เพื่ออ่านข้อมูลบริบทที่ตั้งไว้ ตัวอย่างเช่น:
API ข้างต้นทั้งหมดส่งคืนค่าของคุณสมบัติเฉพาะบริบท และ API เหล่านี้สามารถนำเข้าได้โดยใช้คำสั่งการใช้งานที่อธิบายไว้ก่อนหน้านี้
หลังจากกำหนดฟังก์ชัน get_context() เราสามารถเขียนเนื้อหาการทดสอบหน่วยทีละรายการในโมดูลทดสอบ
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 ทันทีคือการประกาศของ unit test function set_get_message()
บรรทัดที่ 3-10 ของโค้ดเป็นตรรกะการทดสอบหลักภายในฟังก์ชันการทดสอบหน่วย โดยที่การนำโค้ดไปใช้ก่อนเรียก get_context ที่กำหนดไว้ก่อนหน้านี้เพื่อเริ่มต้นบริบทบริบทที่ใช้ในสภาพแวดล้อมการทดสอบ นอกจากนี้ เป็นมูลค่าการกล่าวขวัญว่าเนื่องจากการทดสอบหน่วยนี้จำเป็นต้องเขียนข้อมูลไปยังข้อมูลสถานะของสัญญา จึงจำเป็นต้องตั้งค่าพารามิเตอร์สำหรับ get_context และตั้งค่าแอตทริบิวต์ is_view ใน VMContext ที่กล่าวถึงข้างต้นเป็นเท็จ มิฉะนั้นจะเกิดความตื่นตระหนก ถูกเรียกใช้ในการทดสอบหน่วย การทดสอบล้มเหลว
หลังจากตั้งค่าบริบทการดำเนินการตามสัญญาที่สมเหตุสมผลแล้ว บรรทัดที่ 4 ของโค้ดจะใช้บริบท VMContext เพื่อใช้มาโคร testing_env! เพื่อเริ่มต้นอินสแตนซ์ MockedBlockchain สำหรับการโต้ตอบสัญญาอัจฉริยะ บรรทัดที่ 5 ของโค้ดจะเรียก StatusMessage::default() ที่กำหนดไว้ในโมดูลพาเรนต์เพื่อสร้างสัญญาวัตถุสัญญาที่เริ่มต้น"Hello"ในโค้ดที่ตามมา การทดสอบจะเรียกเมธอด set_status ที่กำหนดโดยโมดูลหลัก StatusMessage เพื่อบันทึกสตริงในข้อมูลสถานะสัญญา"assertion failed". จากนั้นใช้ get_status เพื่ออ่านข้อมูลบางส่วนจากข้อมูลสถานะสัญญา และเปรียบเทียบกับเนื้อหาที่คาดไว้ ผ่านการทดสอบหน่วยนี้หากเนื้อหาตรงกัน ให้เริ่มเธรดการทดสอบนี้หากไม่ตรงกัน
ประเภทของความตื่นตระหนก
วิธีการเขียนของการใช้ assert เพื่อตรวจสอบใน unit test มีดังนี้
assert_eq!(left,มาโคร assert!(expression) สามารถตรวจสอบค่าบูลีน และผ่านการทดสอบก็ต่อเมื่อเนื้อหาที่อ้างถึงโดย expression expression นั้นเป็นจริงเท่านั้น
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 ของโค้ดเริ่มต้นสถานะของสัญญาทั้งหมดเท่านั้น ข้อมูลสัญญาในขณะนี้จึงว่างเปล่าทั้งหมด ดังนั้นค่าที่ส่งคืนจะเป็นไม่มี ในที่สุด เนื่องจากผลลัพธ์เป็นไปตามคาด การยืนยันจึงถูกต้องและการทดสอบหน่วยสามารถผ่านได้
4. ดำเนินการกรณีทดสอบ
[dependencies]
near-sdk = "3.1.0"
หลังจากเขียนการทดสอบหน่วยข้างต้นแล้ว เรายังจำเป็นต้องกำหนดค่าไฟล์ Cargo.toml ของสัญญาในโครงการ StatusMessage Rust นั่นคือ เพิ่มการพึ่งพาบน Near-sdk ในส่วน [การพึ่งพา] ของไฟล์ (หมายเลขเวอร์ชันคือ 3.1. 0).
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
use near_sdk::collections::LookupMap;
use near_sdk::{env, near_bindgen};
ในขณะเดียวกัน เราจำเป็นต้องอิมพอร์ตโมดูลหรือแพ็คเกจเหล่านี้จาก near_sdk ที่จุดเริ่มต้นของไฟล์ src/lib.rs:
$ cargo test --package status-message
หลังจากกำหนดค่าการพึ่งพาของโครงการสัญญาแล้ว เราสามารถใช้สินค้าเพื่อดำเนินการกรณีการทดสอบหน่วยทั้งหมด คำสั่งเฉพาะมีดังนี้:
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
สรุปและแสดงตัวอย่างของปัญหานี้
สรุปและแสดงตัวอย่างของปัญหานี้