用松露测试以太坊事件日志
Posted
技术标签:
【中文标题】用松露测试以太坊事件日志【英文标题】:Test ethereum Event Logs with truffle 【发布时间】:2016-08-06 06:44:06 【问题描述】:我有一个合约函数,它会在每次调用时发出事件。
我想在每个通过的测试上发出一个事件,这里有一些测试:
it("should emit Error event when sending 5 ether", function(done)
var insurance = CarInsurance.deployed();
insurance.send(from: accounts[0], value: web3.toWei(5, 'ether')).then(done).catch(done);
);
it("should emit Error event when sending 5 ether", function(done)
var insurance = CarInsurance.deployed();
insurance.send(from: accounts[0], value: web3.toWei(5, 'ether')).then(function(txHash)
assert.notEqual(txHash, null);
).then(done).catch(done);
);
it("should emit Error event when sending 5 ether", function(done)
var insurance = CarInsurance.deployed();
insurance.send(from: accounts[0], value: web3.toWei(5, 'ether')).then(function(done)
done();
).catch(done);
);
结果是:
1) should emit Error event when sending 5 ether
Events emitted during test:
---------------------------
Error(error: Must send 10 ether)
---------------------------
✓ should emit Error event when sending 5 ether (11120ms)
✓ should emit Error event when sending 5 ether (16077ms)
3 passing (51s)
1 failing
1) Contract: CarInsurance should emit Error event when sending 5 ether:
Error: done() invoked with non-Error: 0x87ae32b8d9f8f09dbb5d7b36267370f19d2bda90d3cf7608629cd5ec17658e9b
您可以看到唯一记录的失败。
有什么想法吗?
谢谢
【问题讨论】:
【参考方案1】:我能够找到一些参考资料来帮助解决这个问题,特别是如果您想使用 async/await。
it('can create a unique star and get its name', async function ()
const event = this.contract.starClaimed();
event.watch(async (err, result) =>
if (err) console.log("Somethings wrong...");
if (result.args.owner === accounts[0])
let token = result.args._token;
event.stopWatching;
const star = await this.contract.tokenIdToStarInfo(token);
assert.equal(star[0], 'awesome star!');
assert.equal(star[1], 'yada yada yada');
assert.equal(star[2], 'dec_test');
assert.equal(star[3], 'mag_test');
assert.equal(star[4], 'cent_test');
);
await this.contract.createStar('awesome star!', 'yada yada yada', 'dec_test', 'mag_test', 'cent_test', from: accounts[0]);
);
这是我找到的参考资料:https://github.com/trufflesuite/truffle-contract/issues/117
【讨论】:
【参考方案2】:除了自己写,你也可以使用 Truffle 的测试工具expectEvent.js:
const inLogs = require('openzeppelin-solidity/test/helpers/expectEvent')
require('chai').use(require('chai-bignumber')(BigNumber)).should()
...
logs: this.logs = await this.token.burn(amount, from: owner )
...
const event = inLogs(this.logs, 'Burn')
event.args.burner.should.eq(owner)
event.args.value.should.be.bignumber.equal(amount)
可以在 Truffle 的BurnableToken.behavior.js 中找到一个示例。
【讨论】:
【参考方案3】:您可以使用truffle-assertions
包,它有一个断言来检查是否已发出事件。它还可以选择传递过滤器函数以检查事件参数的复杂条件。
npm install truffle-assertions
您可以在测试文件的顶部导入它:
const truffleAssert = require('truffle-assertions');
并在你的测试中使用它:
let txResult = await insurance.send(from: accounts[0], value: web3.toWei(5, 'ether'));
truffleAssert.eventEmitted(txResult, 'Error', (ev) =>
return ev.error === 'Must send 10 ether';
免责声明:我创建了这个包以在我自己的测试中使用,并且通过添加过滤器功能,可以以非常直接的方式检查事件参数的复杂条件。我在博客上写了an article explaining this in more detail。
【讨论】:
【参考方案4】:有一个助手可以做到这一点:
npm install --save truffle-test-utils
在测试的顶部:
require('truffle-test-utils').init();
在你的测试中:
let result = await insurance.send(from: accounts[0], value: web3.toWei(5, 'ether'));
assert.web3Event(result,
event: 'Error',
args:
error: 'Must send 10 ether'
, 'Error event when sending 5 ether');
完全披露:我是这个包的作者。我在 SO 上寻找这样的解决方案后写了它,但找不到它。
【讨论】:
【参考方案5】:从 Truffle v3 开始,您可以在回调结果中获得日志。所以你可以这样做:
insurance.send(from: accounts[0], value: web3.toWei(5, 'ether')).then((result) =>
assert.equal(result.logs[0].event, "Error", "Expected Error event")
)
见https://github.com/trufflesuite/truffle-contract#processing-transaction-results
【讨论】:
【参考方案6】:您正在将 tx 哈希传递给 done() 函数。我认为问题出在:
insurance.send(from: accounts[0], value: web3.toWei(5, 'ether')).then(done).catch(done);
改成:
insurance.send(from: accounts[0], value: web3.toWei(5, 'ether')).then(function() done(); ).catch(done);
测试事件:
it("should check events", function(done)
var watcher = contract.Reward();
// we'll send rewards
contract.sendReward(1, 10000, from: accounts[0]).then(function()
return watcher.get();
).then(function(events)
// now we'll check that the events are correct
assert.equal(events.length, 1);
assert.equal(events[0].args.beneficiary.valueOf(), 1);
assert.equal(events[0].args.value.valueOf(), 10000);
).then(done).catch(done);
);
【讨论】:
事实上,只有第一个测试输出了我想要的“错误”事件。当我像你说的那样改变时,它什么也不输出,似乎在等待 done()... @user3262670 我根本看不到任何对测试中事件的检查。 + 所有测试用例都被命名为“发送 5 个以太时应该发出错误事件”,所以你无法判断它们中的哪一个失败。 我们可以在 test 中检查事件吗?我想展示执行相同测试用例的三种方法。我只想在测试期间显示事件,唯一的方法是在测试失败时...... @user3262670 我添加了一个如何在 Truffle 中测试事件的示例。 truffle 是否支持直接从solidity 测试事件?以上是关于用松露测试以太坊事件日志的主要内容,如果未能解决你的问题,请参考以下文章