<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Hardhat是一個開源的以太坊開發框架,簡單好用、可延伸、可客製化的特點讓它在開發者中間很受歡迎。Hardhat在支援編輯、編譯、偵錯和部署合約方面都非常的方便,也有很多功能可以使合約測試工作更加高效和便捷,本文就是聚焦在合約測試領域,探尋Hardhat的特點和日常測試過程中的一些使用技巧。
可以參考Hardhat官網教學,進行環境的準備和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();
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");
//最簡單的判斷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();
在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合約測試的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45