TronBox 使用 Mocha测试框架和 Chai进行断言,为你提供了一个可靠的框架来编写你的 JavaScript 测试。让我们深入了解 TronBox 如何在 Mocha 基础上方便测试合约。
注意:如果你不熟悉在 Mocha 中编写单元测试,请在继续之前查看 Mocha 文档。
使用 contract() 而不是 describe()
在结构上,单元测试应该与 Mocha 的测试基本保持不变:测试文件应该存在于 ./test
目录中,它们应该以扩展名 .js
结尾,并且它们应该包含 Mocha 将识别为自动化测试的代码。TronBox 测试与 Mocha 测试的不同之处在于它的 contract()
功能。
- 在运行每个单测的
contract()
函数之前,合约会重新部署到正在运行的波场网络中。因此,其中的测试过程都是在干净的合约状态下运行。 - 该
contract()
功能提供了当前波场网络可用的帐户列表,可以使用它来编写测试。
在测试中使用合约抽象
合约抽象(Contract abstraction)是通过 Javascript 与波场合约交互的基础。因为 TronBox 无法检测你在测试中需要与哪些合约进行交互,所以需要我们明确写出这些合约。你可以使用 TronBox 提供的 artifacts.require()
方法来执行此操作,该方法允许你为特定的 Solidity 合约请求一个可用的合约抽象。正如你将在下面的示例中看到的那样,可以使用此抽象来确保你的合约正常工作。
有关更多使用合约抽象的信息,请参阅 与合约进行交互 部分。
使用 artifacts.require()
在测试中使用 artifacts.require()
与在迁移中使用它的方式相同;你只需要传递合同的名称。有关详细用法,请参阅迁移部分中的 artifacts.require() 文档 。
使用 tronWarp
每个测试文件中都有一个 tronWarp
实例,可直接引用,就像 tronWrap.trx.getBalance(account)
就行了。
案例
使用 .then
.then
这是MetaCoin TronBox Box中使用 async/await 表示法提供的示例测试。注意 contract()
函数的使用,使用 accounts
指定可用波场账户的数组,以及使用 artifacts.require()
来直接与合约交互。
文件: ./test/metacoin.js
const MetaCoin = artifacts.require('MetaCoin');
contract('MetaCoin', accounts => {
it('should put 10000 MetaCoin in the first account', () =>
MetaCoin.deployed()
.then(instance => instance.getBalance.call(accounts[0]))
.then(balance => {
assert.equal(balance.valueOf(), 10000, "10000 wasn't in the first account");
}));
it('should call a function that depends on a linked library', () => {
let meta;
let metaCoinBalance;
let metaCoinConvertedBalance;
return MetaCoin.deployed()
.then(instance => {
meta = instance;
return meta.getBalance.call(accounts[0]);
})
.then(outCoinBalance => {
metaCoinBalance = outCoinBalance.toNumber();
return meta.getConvertedBalance.call(accounts[0]);
})
.then(outCoinConvertedBalance => {
metaCoinConvertedBalance = outCoinConvertedBalance.toNumber();
})
.then(() => {
assert.equal(metaCoinConvertedBalance, 2 * metaCoinBalance, 'Library function returned unexpected function, linkage may be broken');
});
});
it('should send coin correctly', () => {
let meta;
// Get initial balances of first and second account.
const account_one = accounts[0];
const account_two = accounts[1];
let account_one_starting_balance;
let account_two_starting_balance;
let account_one_ending_balance;
let account_two_ending_balance;
const amount = 10;
return MetaCoin.deployed()
.then(instance => {
meta = instance;
return meta.getBalance.call(account_one);
})
.then(balance => {
account_one_starting_balance = balance.toNumber();
return meta.getBalance.call(account_two);
})
.then(balance => {
account_two_starting_balance = balance.toNumber();
return meta.sendCoin(account_two, amount, { from: account_one });
})
.then(() => meta.getBalance.call(account_one))
.then(balance => {
account_one_ending_balance = balance.toNumber();
return meta.getBalance.call(account_two);
})
.then(balance => {
account_two_ending_balance = balance.toNumber();
assert.equal(account_one_ending_balance, account_one_starting_balance - amount, "Amount wasn't correctly taken from the sender");
assert.equal(account_two_ending_balance, account_two_starting_balance + amount, "Amount wasn't correctly sent to the receiver");
});
});
});
该测试将产生以下输出:
Contract: MetaCoin
√ should put 10000 MetaCoin in the first account (83ms)
√ should call a function that depends on a linked library (43ms)
√ should send coin correctly (122ms)
3 passing (293ms)
使用 async/await
下面是一个类似的例子,但使用了async/await:
const MetaCoin = artifacts.require('MetaCoin');
contract('2nd MetaCoin test', async accounts => {
it('should put 10000 MetaCoin in the first account', async () => {
let instance = await MetaCoin.deployed();
let balance = await instance.getBalance.call(accounts[0]);
assert.equal(balance.valueOf(), 10000);
});
it('should call a function that depends on a linked library', async () => {
let meta = await MetaCoin.deployed();
let outCoinBalance = await meta.getBalance.call(accounts[0]);
let metaCoinBalance = outCoinBalance.toNumber();
let outCoinConvertedBalance = await meta.getConvertedBalance.call(accounts[0]);
let metaCoinConvertedBalance = outCoinConvertedBalance.toNumber();
assert.equal(metaCoinConvertedBalance, 2 * metaCoinBalance);
});
it('should send coin correctly', async () => {
// Get initial balances of first and second account.
let account_one = accounts[0];
let account_two = accounts[1];
let amount = 10;
let instance = await MetaCoin.deployed();
let meta = instance;
let balance = await meta.getBalance.call(account_one);
let account_one_starting_balance = balance.toNumber();
balance = await meta.getBalance.call(account_two);
let account_two_starting_balance = balance.toNumber();
await meta.sendCoin(account_two, amount, { from: account_one });
balance = await meta.getBalance.call(account_one);
let account_one_ending_balance = balance.toNumber();
balance = await meta.getBalance.call(account_two);
let account_two_ending_balance = balance.toNumber();
assert.equal(account_one_ending_balance, account_one_starting_balance - amount, "Amount wasn't correctly taken from the sender");
assert.equal(account_two_ending_balance, account_two_starting_balance + amount, "Amount wasn't correctly sent to the receiver");
});
});
这个测试的输出与上一个例子相同。
特定测试
你可以单独运行 test 目录下的某一个特定文件,如下所示:
tronbox test ./test/metacoin.js
更多信息请参见完整的命令手册 。