使用Truffle测试以太坊事件日志

12

我有一个合约函数,每次调用都会发出事件。

我希望在每个通过测试时发出一个事件,以下是一些测试:

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

你可以看到只有一个失败的日志。

有什么想法吗?

谢谢

6个回答

12
你正在将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()... - ltheron
@user3262670,我根本没看到测试中有任何检查事件的部分。此外,所有测试用例的名称都是“当发送5个以太时应发出错误事件”,因此您无法确定哪个失败了。 - Aldekein
我们可以在测试中检查事件吗?我想展示三种执行相同测试用例的方式。我只想在测试期间显示事件,而唯一的方法是当测试失败时... - ltheron
@user3262670 我已经添加了一个在Truffle中测试事件的示例。 - Aldekein
1
Truffle是否支持直接从Solidity测试事件? - cayblood

6

5
有一个助手可以做到这一点:
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');

完全披露:我是这个软件包的作者。我在 Stack Overflow 上寻找了这样的解决方案,但却没有找到。


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 中找到。

0
您可以使用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';
}

免责声明:我创建了这个包来在自己的测试中使用,并通过添加过滤函数,可以以非常简单的方式检查事件参数的复杂条件。我在我的博客上写了一篇更详细解释此内容的文章


0

我能找到一些参考资料来帮助你,特别是如果你想使用 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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接