BTC
ETH
HTX
SOL
BNB
ดูตลาด
简中
繁中
English
日本語
한국어
ภาษาไทย
Tiếng Việt

ไดอารี่การพัฒนาสัญญาสมาร์ทสนิม (2)

BlockSec
特邀专栏作者
2022-03-29 10:26
บทความนี้มีประมาณ 4743 คำ การอ่านทั้งหมดใช้เวลาประมาณ 7 นาที
เขียนกรณีทดสอบหน่วยสัญญาสมาร์ทสนิม
สรุปโดย AI
ขยาย
เขียนกรณีทดสอบหน่วยสัญญาสมาร์ทสนิม

บทความที่เกี่ยวข้อง:

  • ข้อความ

ไดอารี่การพัฒนาสัญญาสมาร์ทสนิม (1) คำจำกัดความของข้อมูลสถานะสัญญาและการนำไปใช้

ในบทความ 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

สรุปและแสดงตัวอย่างของปัญหานี้

สรุปและแสดงตัวอย่างของปัญหานี้

สัญญาที่ชาญฉลาด
ค้นหา
สารบัญบทความ
คลังบทความของผู้เขียน
BlockSec
ดาวน์โหลดแอพ Odaily พลาเน็ตเดลี่
ให้คนบางกลุ่มเข้าใจ Web3.0 ก่อน
IOS
Android