Truffle — 智能合約測試流程簡易操作教學

ivesH
14 min readJan 5, 2021

--

本文將不多介紹Truffle是什麼工具,先假設各位已經知道其用途。本文也不會詳細介紹Truffle所有指令,純粹介紹對於智能合約開發者在測試時基本會有的流程。

若真的還不太知道Truffle的用途,可至官方Docs學習!

也請在Docs跟著說明先進行Truffle的安裝。

本文將使用open-zeppelin的ERC20範例合約進行示範,智能合約程式碼:

記得將此智能合約相關之所有智能合約都放在後面會提到的contracts/資料夾內!

另外測試網路(鏈)是直接使用Ganache啟動單機網路(鏈),較為簡單方便。

故後面會提到的truffle-config.js當中,記得將networks設定為:

development: {
host: "127.0.0.1",
port: 7545,
network_id: "*"
}

(1) 初始化 — truffle init

$ truffle initStarting init...
================
> Copying project files to /yourWorkspaceDir
Init successful, sweet!

這個步驟會自動幫你產生truffle所需的基本檔案架構,包含contracts/、migrations/、truffle-config.js。其中contracts/Migrations.sol與migrations/1_initial_migration.js在後續測試當中都需要保留。

(2) 編譯合約 — truffle compile

$ truffle compileCompiling your contracts...
===========================
> Compiling ./contracts/GSN/Context.sol
> Compiling ./contracts/Migrations.sol
> Compiling ./contracts/math/SafeMath.sol
> Compiling ./contracts/token/ERC20/ERC20.sol
> Compiling ./contracts/token/ERC20/IERC20.sol
> Artifacts written to /yourWorkspaceDir/build/contracts
> Compiled successfully using:
- solc: 0.6.1+commit.e6f7d5a4.Emscripten.clang

這個步驟會去編譯合約(若程式碼有錯誤就不會成功,錯誤訊息會顯示在console中),並將該合約的相關資訊(像是abi、bytecode之類的)透過json格式存於build/contracts當中。

在此有遇到一個小地方需要注意,第一次執行時,出現這樣的錯誤:

Error: Truffle is currently using solc 0.5.16, but one or more of your contracts specify "pragma solidity >=0.6.0 <0.8.0".Please update your truffle config or pragma statement(s).(See https://trufflesuite.com/docs/truffle/reference/configuration#compiler-configuration for information onconfiguring Truffle to use a specific solc compiler version.)

原因在於一開始init時,產生truffle-config.js設定檔當中,compilers.solc的所有設定都是註解掉的(使用預設的意思)。所以在將compilers.solc.version設定為”0.6.1"之後即可正常執行build了!(這裡設定0.6.1是因為open-zeppelin的ERC20相關合約都是使用 pragma solidity >=0.6.0 <0.8.0;,所以truffle預設的0.5.16並不符合智能合約程式碼的版本。

(3) deploy合約 — truffle migrate

首先是將合約deploy到測試鏈當中,這裡需要對migrations/中的檔案進行編輯。基本要deploy合約的話會需要這兩個檔案:

.
├── 1_initial_migration.js
└── 2_deploy_contracts.js //一開始沒有這個檔案,要自己增加

1_initial_migration.js這個檔案跟contracts/Migrations.sol一樣,都不要刪掉它,是用來管理智能合約用的。

主要是要透過2_deploy_contracts.js來進行合約的deploy,以下是基本寫法:

const ERC20 = artifacts.require("ERC20");module.exports = function(deployer) {
deployer.deploy(ERC20, "test2", "TST2");
};

接著就可以透過truffle migrate進行合約deploy(此步驟一樣會執行編譯),記得先確認truffle-config.js當中是否已設定好networks

$ truffle migrateCompiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.
Starting migrations...
======================
> Network name: 'development'
> Network id: 5777
> Block gas limit: 6721975 (0x6691b7)
1_initial_migration.js
======================
Replacing 'Migrations'
----------------------
> transaction hash: 0xfd62a74ad818a31c00e7dad9354c9706430e546902f6199d0a82d891c1538d48> Blocks: 0 Seconds: 0
> contract address: 0x9cE0e40E5392A5996672377B9c3E65f605e95A36
> block number: 9
> block timestamp: 1609814807
> account: 0x4faB2E6E916859F5fb06d445008cA0A8EeD402A2
> balance: 99.94315274
> gas used: 192159 (0x2ee9f)
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.00384318 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.00384318 ETH
2_deploy_contracts.js
=====================
Replacing 'ERC20'
-----------------
> transaction hash: 0xddb085bc4dd2220588a42f5fb47d4cd32eec9231b4c8556b5c2d2295cd10dee5
> Blocks: 0 Seconds: 0
> contract address: 0xBb70762e5B5ADE326Dbb8F86f93b72BF0C41399b
> block number: 11
> block timestamp: 1609814807
> account: 0x4faB2E6E916859F5fb06d445008cA0A8EeD402A2
> balance: 99.92104016
> gas used: 1063291 (0x10397b)
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.02126582 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.02126582 ETH
Summary
=======
> Total deployments: 2
> Final cost: 0.025109 ETH

deploy成功的話,會顯示該筆交易的詳細內容,也包含合約地址。

但當你想再次deploy的時候,若智能合約程式碼沒有變動,會顯示:

$ truffle migrateCompiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.
Network up to date.

此時就要將指令加上 — reset即可

$ truffle migrate --reset

(4) 操作智能合約 — truffle console

首先輸入指令進入console

$ truffle console
truffle(development)>

接著可以用兩種方法來跟合約互動:

(a) 對最近一個deploy的合約互動

truffle(development)> let instance = await ERC20.deployed()
undefined
truffle(development)> instance.name()
'test2'

(b) 對之前deploy過的某個合約互動(要知道合約地址)

truffle(development)> let instance = await ERC20.at("0xBb70762e5B5ADE326Dbb8F86f93b72BF0C41399b")
undefined
truffle(development)> instance.symbol()
'TST2'

如此一來就可以透過指令的方式來呼叫智能合約上的function,進行簡易的測試。

(5) 測試智能合約 — truffle test

透過truffle console的方式也能夠測試智能合約沒錯,但不可能每一次都要慢慢的一行一行打指令進行測試。所以truffle也可以使用類似自動化script的方式進行測試(類似在寫js的unit test)。

將測試script放在test/當中,而官方表示可以使用兩種語言進行測試,分別是JS以及Solidity。

以下使用JS進行測試:

首先在test/中建立檔案ERC20.test.js

const ERC20 = artifacts.require('ERC20');contract('ERC20', function () {
const tokenName = 'test2';
const tokenSymbol = 'TST2';
it(`should return Name:${tokenName}, Symbol:${tokenSymbol}`, async () => {
let instance = await ERC20.deployed();
let name = await instance.name.call();
let symbol = await instance.symbol.call();
assert.equal(name, tokenName, "Name不正確");
assert.equal(symbol, tokenSymbol, "Symbol不正確");
});
});

tokenName與tokenSymbol分別設定為’test2'、’TST2'是跟前面2_deploy_contracts.js中設定的一樣。程式碼當中的合約互動方式基本上與truffle console操作相同,主要在assert的判斷部分。

這裡只是很單純的用呼叫name、symbol來當成範例,實際可以測試的東西還非常多,例如:transfer、approve之類ERC20合約常用功能。也可以參考open-zeppelin的測試程式

執行測試:

$ truffle testUsing network 'development'.
Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.
Contract: ERC20
✓ should return Name:test2, Symbol:TST2 (56ms)
1 passing (153ms)

以上便是一個很基本的truffle使用範例,適合剛接觸Ethereum Smart Contract的開發者,希望對各位有幫助!

最終資料夾檔案架構:

$ tree .
.
├── build
│ └── contracts
│ ├── Context.json
│ ├── ERC20.json
│ ├── IERC20.json
│ ├── Migrations.json
│ └── SafeMath.json
├── contracts
│ ├── GSN
│ │ └── Context.sol
│ ├── Migrations.sol
│ ├── math
│ │ └── SafeMath.sol
│ ├── token
│ │ └── ERC20
│ │ ├── ERC20.sol
│ │ └── IERC20.sol

├── migrations
│ ├── 1_initial_migration.js
│ └── 2_deploy_contracts.js
├── test
│ └── ERC20.test.js
└── truffle-config.js

--

--

No responses yet

Write a response