您好,登錄后才能下訂單哦!
這篇文章主要介紹了Hardhat怎么進行合約測試環境準備的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇Hardhat怎么進行合約測試環境準備文章都會有所收獲,下面我們一起來看看吧。
Hardhat是一個開源的以太坊開發框架,簡單好用、可擴展、可定制的特點讓它在開發者中間很受歡迎。Hardhat在支持編輯、編譯、調試和部署合約方面都非常的方便,也有很多功能可以使合約測試工作更加高效和便捷。
可以參考Hardhat官網教程,進行環境的準備和Hardhat安裝。
Hardhat提供了快速構建合約工程的方法:
建立空的工程目錄
在目錄下執行npx hardhat
根據交互提示完成Hardhat工程的創建
快速創建Hardhat工程,可以在contract目錄下看到Lock.sol的合約,此合約是一個簡單的示例,實現了在指定時間前(unlockTime)鎖定資產的功能。
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9; // Uncomment this line to use console.log import "hardhat/console.sol"; contract Lock { uint public unlockTime; address payable public owner; event Withdrawal(uint amount, uint when); constructor(uint _unlockTime) payable { require( block.timestamp < _unlockTime, "Unlock time should be in the future" ); unlockTime = _unlockTime; owner = payable(msg.sender); } function withdraw() public { // Uncomment this line, and the import of "hardhat/console.sol", to print a log in your terminal console.log("Unlock time is %o and block timestamp is %o", unlockTime, block.timestamp); require(block.timestamp >= unlockTime, "You can't withdraw yet"); require(msg.sender == owner, "You aren't the owner"); emit Withdrawal(address(this).balance, block.timestamp); owner.transfer(address(this).balance); } }
同時,在test目錄下,有Lock.ts(或Lock.js)的測試代碼,測試代碼里分別展示了對合約部署,合約中涉及的功能的測試。其中值得學習的部分:
一是定義了一個具有setup功能的函數,此函數定義了一些狀態變量的初始狀態,后面在每次測試代碼運行前,可以通過loadFixture方法執行此函數,把狀態變量還原到函數中定義的初始狀態。這種給狀態變量取快照,并用快照還原的方式,解決了很多因為狀態變量改變而測試用例執行異常的問題,是個很有用很便捷的方法。
另一個是用到了很便捷的斷言方式,這就省掉了寫很多麻煩的校驗條件,來驗證一個執行結果。比如下面這個斷言,直接能驗證當withdraw函數被調用后出現的回滾情況:
await expect(lock.withdraw()).to.be.revertedWith( "You can't withdraw yet" );
使用場景
用于每次執行測試前的setup操作,可以定義一個函數,在此函數中完成諸如合約部署,合約初始化,賬戶初始化等操作,在每次執行測試前利用loadFixture的功能,進行相同的變量狀態的設置,對合約測試提供了很大的幫助。
工作原理
根據Hardhat源碼,可以看到loadFixture維護了一個快照數組snapshots,一個快照元素包含:
不同的函數f作為loadFixture入參時,會有不同的snapshot存儲在loadFixture維護的snapshots數組中。
在loadFixture(f)首次執行時,屬于f函數的snapshot為undefined,此時會記錄f函數中定義的全部狀態變量,同時執行:
const restorer = await takeSnapshot();
并將此時的snapshot元素加入到snapshots數組中,后面再次用到同一個入參函數f的loadFixture時,在快照數組snapshots中已存在快照,可直接進行區塊鏈狀態回滾: await snapshot.restorer.restore();
fixture: Fixture類型的入參函數,type Fixture = () => Promise;
data:fixture函數中定義的狀態變量
restorer:一個有restore方法的結構體,在“./helpers/takeSnapshot”方法中有定義,可以觸發evm_revert操作,指定區塊鏈退回到某個快照點。
loadFixture的用法
官方文檔示例如下:
```js async function deployContractsFixture() { const token = await Token.deploy(...); const exchange = await Exchange.deploy(...); return { token, exchange }; } it("test", async function () { const { token, exchange } = await loadFixture(deployContractsFixture); // use token and exchanges contracts }) ``` 注意:loadFixture的入參不可以是匿名函數,即: ```js //錯誤寫法 loadFixture(async () => { ... }) //正確寫法 async function beforeTest(){ //定義函數 } loadFixture(beforeTest); ```
Machers:在chai斷言庫的基礎上增加了以太坊特色的斷言,便于測試使用
1.Events用法
contract Ademo { event Event(); function callFunction () public { emit Event(); } }
對合約C的call方法進行調用會觸發一個無參數事件,為了測試這個事件是否被觸發,可以直接用hardhat-chai-matchers中的Events斷言,用法如下:
const A=await ethers.getContractFactory("Ademo"); const a=await A.deploy(); //采用hardhat-chai-matchers的斷言方式,判斷Events是否觸發 await expect(a.callFunction()).to.emit(a,"Event");
Reverts用法:
//最簡單的判斷revert的方式 await expect(contract.call()).to.be.reverted; //判斷未發生revert await expect(contract.call()).not.to.be.reverted; //判斷revert發生并且帶了指定的錯誤信息 await expect(contract.call()).to.be.revertedWith("Some revert message"); //判斷未發生revert并且攜帶指定信息 await expect(contract.call()).not.to.be.revertedWith("Another revert message");
除了上述常用的判斷場景外,hardhat-chai-matchers還支持了對Panic以及定制化Error的判定:
await expect(…).to.be.revertedWithPanic(PANIC_CODES) await expect(…).not.to.be.revertedWithPanic(PANIC_CODES) await expect(…).to.be.revertedWithCustomError(CONTRACT,"CustomErrorName") await expect(…).to.be.revertedWithoutReason();
Big Number
在solidity中最大整型數是2^256,而JavaScript中的最大安全數是2^53-1,如果用JS寫solidity合約中返回的大數的斷言,就會出現問題。hardhat-chai-matchers提供了關于大數的斷言能力,使用者無需關心大數之間比較的關系,直接以數字的形式使用即可,比如: expect(await token.balanceOf(someAddress)).to.equal(1);
關于JavaScript的最大安全數問題:
Number.MAX_SAFE_INTEGER 常量表示在 JavaScript 中最大的安全整數,其值為2^53-1,即9007199254740991 。因為Javascript的數字存儲使用了IEEE 754中規定的雙精度浮點數數據類型,而這一數據類型能夠安全存儲(-2^53-1 ~ 2^53-1)之間的數(包括邊界值),超出范圍后將會出現錯誤,比如:
const x = Number.MAX_SAFE_INTEGER + 1; const y = Number.MAX_SAFE_INTEGER + 2; console.log(Number.MAX_SAFE_INTEGER); // Expected output: 9007199254740991 console.log(x); console.log(y); // Expected output: 9007199254740992 console.log(x === y); // Expected output: true
Balance Changes
可以很方便的檢測用戶錢包的資金變化額度,適用于以太幣的金額變化,或者ERC-20代幣的金額變化。
單個錢包地址的金額變化:
await expect(() => sender.sendTransaction({ to: someAddress, value: 200 }) ).to.changeEtherBalance(sender, "-200"); await expect(token.transfer(account, 1)).to.changeTokenBalance( token, account, 1 );
也可以用來檢測多個賬戶的金額變化,在測試轉賬交易時,非常適用:
await expect(() => sender.sendTransaction({ to: receiver, value: 200 }) ).to.changeEtherBalances([sender, receiver], [-200, 200]); await expect(token.transferFrom(sender, receiver, 1)).to.changeTokenBalances( token, [sender, receiver], [-1, 1] );
字符串比較
可以用hardhat-chai-matchers提供的方法,方便地校驗各種復雜的字符串,比如一個字符串是否是正確的地址格式、私鑰格式等,用法如下:
// 是否符合address格式 expect("0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2").to.be.a.properAddress; //是否符合私鑰格式 expect(SOME_PRI_KEY).to.be.a.properPrivateKey; //判斷十六進制字符串的用法 expect("0x00012AB").to.hexEqual("0x12ab"); //判斷十六進制字符串的長度 expect("0x123456").to.be.properHex(6);
關于“Hardhat怎么進行合約測試環境準備”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“Hardhat怎么進行合約測試環境準備”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。