如何撰寫智能合約(Smart Contract)?(IV)加入單元測試
因為智能合約一旦部署就難以修改,因此合約的安全性極其重要,要避免合約中出現一些基礎錯誤,除了透過第三方驗證外,完整地單元測試 (unit test) 也是必需的。
目前最成熟的智能合約單元測試方式,還是透過Truffle開發框架來達成。有趣的是 Truffle 主要使用 Javascript 來撰寫智能合約的單元測試(也可以用 solidity 來寫)。
加入測試
接續上一篇建立的HelloToken合約,在test/目錄下加入test_hello_token.js測試檔案(如果覺得這份程式碼不易理解,可跳過這節,後面會介紹更簡潔的測試方法,到時再回來對照著看)。
var HelloToken = artifacts.require('HelloToken');
const INITIAL_SUPPLY = 100000;
let _totalSupply;
contract('HelloToken', function(accounts) {
it('should met initial supply', function() {
var contract;
HelloToken.deployed().then((instance) => {
contract = instance;
return contract.totalSupply.call();
}).then((totalSupply) => {
_totalSupply = totalSupply;
assert.equal(totalSupply.toNumber(), INITIAL_SUPPLY);
return contract.balanceOf(accounts[0]);
}).then((senderBalance) => {
assert.equal(_totalSupply.toNumber(), senderBalance.toNumber());
});
});
});
運行truffle test可看到測試通過的結果。
Contract: HelloToken
✓ should met initial supply
1 passing (11ms)
講解
var HelloToken = artifacts.require('HelloToken');
artifacts.require的用法和在migrations/中的用法相同,可以直接引入對應的智能合約。
contract('HelloToken', function(accounts) {
it('should met initial supply', function() {
});
});
Truffle 是使用 Javascript 開發中常見的Mocha測試框架和Chai斷言庫來做單元測試。差別只是把 Mocha test 中的 describe換成contract。根據官方文件 [^1],contact執行前會自動重新部署到 testrpc (或測試網路) 上,所以智能合約會是剛部署好乾淨的狀態。
此外,contract也會帶入accounts變數,裡面儲存了 testrpc 或其他你運行的測試網路所提供的帳號,開發者可以直接使用這些帳號來測試合約。
第一個測試是來測部署合約後預設的代幣數目是否正確。
var contract;
HelloToken.deployed().then((instance) => {
contract = instance;
return contract.totalSupply.call();
}).then((totalSupply) => {
...
});
這邊內容和在truffle console中輸入的測試內容雷同,使用Promise來確定每個非同步的操作都在上一個操作完成後才繼續執行。
上一個操作可以透過 return 語句回傳下個操作需要的參數。例如這邊then裡面傳入的totalSupply參數,是來自上一行return contract.totalSupply.call()的結果。
assert.equal(totalSupply.toNumber(), INITIAL_SUPPLY);
...
assert.equal(_totalSupply.toNumber(), senderBalance.toNumber());
這邊我們透過assert.equal語句驗證了HelloToken合約中的初始代幣總額與INITIAL_SUPPLY參數的值相符,且與合約部署者 (accounts[0]) 帳戶中擁有的總額相符。