在进行Solidity合约开发时,有一些主流框架,可以帮开发者完成环境准备、工程管理等工作,提高coding的效率,前面介绍过Hardhat的使用,今天再来总结一下Truffle的使用经验。
一、Truffle工程介绍
1. 环境准备
环境依赖:
- NodeJS v8.9.4 或 之后的版本
- Windows, Linux or Mac OS X
运行如下命令,安装truffle
npm install -g truffle
2. 工程结构
我们可以使用truffle提供的truffle box快速搭建truffle工程:
mkdir MetaCoin
cd MetaCoin
truffle unbox metacoin
通过unbox这个叫做MetaCoin的工程,我们可以看到它的目录结构如下所示,在我们自己创建合约工程的时候,从参考样例开始是一个不错的选择。
如果我们需要创建一个空项目,可以在目标路径下用truffle init创建。
MetaCoin
- contracts
- - ConvertLib.sol
- MetaCoin.sol
- Migrations.sol //这是一个单独的 Solidity 文件,用来管理和升级智能合约. 每一个工程都有这样的一个文件,并且通常不需要编辑它。
- migrations
- - 1_initial_migration.js //这是一个部署脚本,用来部署 Migrations 合约,对应 Migrations.sol 文件。
- 2_deploy_contracts.js //这是一个部署脚本,用来部署 MetaCoin 合约. (部署脚本的运行是有顺序的,以2开头的脚本通常在以1开头的脚本之后运行)
- test
- - metacoin.js //Javascript语言编写的测试合约代码,其中用了it("description",function() )语法,搜索了一下,这是Jasmine框架(用来测试JS的一个框架<https://jasmine.github.io/2.2/introduction.html>)
- TestMetaCoin.sol //Solidity语法编写的测试合约
- truffle-config.js // Truffle 配置文件, 用来设置网络信息,和其他项目相关的设置。当我们使用内建的默认的Truffle命令时,这个文件留空也是可以的。
二、合约的部署
我们直接用MetaCoin的合约代码,进行编译和部署。
1.编译合约
在工程目录下,执行:
truffle compile
在本机环境已准备好的情况下,是能够直接顺利编译通过的。
2.启动本地网络
这次实践选用本地develop网络,如果想换成其他网络,可以参考官方文档的网络部分进行配置(learnblockchain.cn/docs/truffl… 运行:
truffle develop
得到以下输出:
进入交互模式后,使用migrate命令部署编译好的智能合约到区块链:
3.交互命令
在 Truffle v5 控制台支持 async/await 方法, 这样让跟合约交互更简单了,方法如下:
(1)从获取部署合约实例
truffle(development)> let instance = await MetaCoin.deployed()
(2)获取账号列表
truffle(development)> let accounts = await web3.eth.getAccounts()
(3)转账
truffle(development)> instance.sendCoin(accounts[1], 500)
(4)检查余额
truffle(development)> let balance = await instance.getBalance(accounts[1])
truffle(development)> balance.toNumber()
尝试:如果交互命令中不加await会如何呢?
truffle(develop)> let ba2=instance.getBalanceInEth(accounts[2])
undefined
truffle(develop)> ba2.toNumber()
evalmachine.<anonymous>:0
ba2.toNumber()
^
Uncaught TypeError: ba2.toNumber is not a function
可见在Truffle中,由于框架与区块链节点交互的操作是异步化的,在使用过程中需要注意用async/await方式获取异步处理结果。
三、合约的测试
1.测试方式
Truffle测试框架支持两种测试方式:
- JavaScript 和TypeScript
- Solidity
所有的测试用例都需要放在./test目录下,truffle只会运行以js,ts,es,es6,jsx,sol为后缀的测试用例
-
运行所有的用例,执行:
- truffle test
-
运行指定的测试用例,执行:
- truffle test ./path/xxx.sol
2.测试运行环境
-
在Ganache或者truffle develop网络运行测试用例时,truffle用快照方式保证每个测试用例之间不会共享数据状态
-
当通过使用如go-ethereum的客户端链接以太网时,truffle会在每个测试用例运行前重新部署合约以保证有一个干净的运行环境
-
运行速度:在Ganache或者truffle develop网络运行测试用例要比通过客户端链接到公共测试网络速度快,大约快90%左右
-
测试建议:在Ganache或者truffle develop上进行开发、调试、测试工作,在临近发布到公网前执行一次测试网络的测试运行
3.编写测试脚本
3.1 用JavaScript写测试用例
Truffle使用Mocha测试框架和chai断言来提供JavaScript写测试用例的框架
Truffle和Mocha的联系与区别:
- truffle是在Mocha的基础上框架
- clean-room特性:Truffle提供了一个新的方法contract(),此方法的其他功能和Mocha的describe()方法相同,特别之处在于truffle使用contract()方法触发了clean-room特性,也就是说在每次contract()运行前,如果是链接以太网络,那每次会重新部署合约,并且contract()方法会提供新的accounts列表以便再将要进行的测试中使用
- truffle仍然可以使用describe()方法,如果要运行的用例不需要使用到clean-room特性,就用describe()
3.2 用Solidity写测试用例
用Solidity写测试用例有几个特点:
- 每运行一次test suite都会有clean-room的环境,
- 可以直接访问部署的合约,可以引入依赖合约
- 测试合约不可以extend from其他合约(功能最小化、为了使你能够完全控制你所写的合约)
- 框架继承了断言库,只要在测试合约开头引用import "truffle/Assert.sol” 即可
- 可以通过任何以太网客户端来运行测试用例
- Truffle通过truffle/DeployedAddresses.sol 来让测试合约获得需要的已部署的合约地址,使用方法:DeployedAddresses.();
- 需要在./test路径之外,引入被测合约源码
- 测试合约名要以Test开头,大写T;
- 测试方法名要以test开头,小写t
- 测试钩子:beforeAll(), beforeEach(), afterAll(), afterEach() 这个和testNg里的钩子类似