使用Truffle直接在Solidity中测试以太坊事件

3
我在使用JavaScript测试Truffle中的事件日志时发现了以下问题:

Test ethereum Event Logs with truffle

。然而,Truffle还支持直接在Solidity中编写测试。但是,我找不到任何关于如何在Solidity中测试事件日志的文档。有人能帮我吗?

你可以在测试中使用Web3。 - yograterol
3个回答

2

1

一般说明:

请注意,智能合约无法访问事件。从设计上来说,事件只能从智能合约外部访问。它们并没有直接存储在区块链中。这意味着您将无法使用纯Solidity进行测试。

日志及其事件数据无法从合约内部访问(甚至不能从创建它们的合约中访问)。 来源:https://solidity.readthedocs.io/en/v0.5.3/contracts.html#events

使用truffle测试事件很简单,请按照以下步骤操作:

1)创建一个简单的合约,该合约发出事件(contracts/EventEmitter.sol):

    pragma solidity 0.5.12;

    contract EventEmitter {

    // ---- EVENTS -----------------------------------------------------------------------------------------------------
    event ConstructorDone(address owner, string message);
    event Counter(uint64 count);

    // ---- FIELDS -----------------------------------------------------------------------------------------------------
    uint64 private _count = 0;
    string constant _message = '0x0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789';

    // ---- CONSTRUCTOR ------------------------------------------------------------------------------------------------
    constructor() public {
        emit ConstructorDone(msg.sender, _message);
    }

    // ---- STATISTICS FUNCTIONS ---------------------------------------------------------------------------------------
    function getCount() public view returns (uint count) {
        return _count;
    }

    // ---- CORE FUNCTIONS ---------------------------------------------------------------------------------------------
    function increment() public {
        _count++;
        emit Counter(_count);
    }
}

2)创建测试合约(test/TestAnEventEmitter.sol):

pragma solidity 0.5.12;

import "truffle/Assert.sol";
import "../contracts/EventEmitter.sol";

contract TestAnEventEmitter {

    EventEmitter private eventEmitter;

    uint eContracts = 0;

    address private owner;

    function assertCount() private {
        Assert.equal(eventEmitter.getCount(), eContracts, "Unexpected count of created contracts");
    }

    constructor() public{
        eventEmitter = new EventEmitter();
        owner = address(this);
    }

}

3)创建测试代码(test/TestAnEventEmitter.js):

const EventEmitter = artifacts.require("EventEmitter");
const truffleAssert = require('truffle-assertions');

/** Expected number of counter */
var eCount = 0;

/** The Contract's instance */
var eventEmitter;

global.CONTRACT_ADDRESS = '';

async function assertContractCount() {
    assert.equal(await eventEmitter.getCount.call(), eCount, "Wrong number of created contracts");
}

contract('EventEmitter', async () => {

    before(async () => {
        eventEmitter = await EventEmitter.new();
    });

    describe("1.1 Basic", function () {

        it("1.1.1 has been created", async () => {
            global.CONTRACT_ADDRESS = eventEmitter.address;
            console.log('        contract => ' + global.CONTRACT_ADDRESS);
            await assertContractCount();
        });

        it("1.1.2 should emit ConstructorDone event", async () => {
            // Get the hash of the deployment transaction
            let txHash = eventEmitter.transactionHash;

            // Get the transaction result using truffleAssert
            let result = await truffleAssert.createTransactionResult(eventEmitter, txHash);

            // Check event
            truffleAssert.eventEmitted(result, 'ConstructorDone', (ev) => {
                console.log('        owner => ' + ev.owner);
                return true;
            });
        });
    });

    describe("1.2 Check calls of increment()", function () {

        it("1.2.1 first call should increase the counts correctly", async () => {
            // Pre-Conditions
            await assertContractCount();

            // Creation
            let tx = await eventEmitter.increment();
            eCount++;

            // Expected Event
            truffleAssert.eventEmitted(tx, 'Counter', (ev) => {
                return parseInt(ev.count) === eCount;
            });

            // Post-Conditions
            await assertContractCount();
        });

        it("1.2.2 second call should increase the counts correctly", async () => {
            // Pre-Conditions
            await assertContractCount();

            // Creation
            let tx = await eventEmitter.increment();
            eCount++;

            // Expected Event
            truffleAssert.eventEmitted(tx, 'Counter', (ev) => {
                return parseInt(ev.count) === eCount;
            });

            // Post-Conditions
            await assertContractCount();
        });

        it("1.2.3 third call should increase the counts correctly", async () => {
            // Pre-Conditions
            await assertContractCount();

            // Creation
            let tx = await eventEmitter.increment();
            eCount++;

            // Expected Event
            truffleAssert.eventEmitted(tx, 'Counter', (ev) => {
                return parseInt(ev.count) === eCount;
            });

            // Post-Conditions
            await assertContractCount();
        });
    });
});

4) 运行测试:

$ truffle test
Using network 'development'.


Compiling your contracts...
===========================
> Compiling ./test/TestAnEventEmitter.sol



  Contract: EventEmitter
    1.1 Basic
        contract => 0xeD62E72c2d04Aa385ec764c743219a93ae49e796
      ✓ 1.1.1 has been created (56ms)
        owner => 0xbD004d9048C9b9e5C4B5109c68dd569A65c47CF9
      ✓ 1.1.2 should emit ConstructorDone event (63ms)
    1.2 Check calls of increment()
      ✓ 1.2.1 first call should increase the counts correctly (142ms)
      ✓ 1.2.2 second call should increase the counts correctly (160ms)
      ✓ 1.2.3 third call should increase the counts correctly (156ms)

完整源代码(包括package.json等): https://github.com/MarkusSprunck/ethereum-event-scan

更多关于事件和监控的信息: https://www.sw-engineering-candies.com/blog-1/Ethereum-Event-Explorer-for-Smart-Contracts

(免责声明:我是这个项目和博客的作者)


0

考虑使用 OpenZeppelin Test Helper expectEvent

以构造期间发出的事件为例:

合约

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;

contract Test {
    address public owner;

    event ContractCreated();

    constructor() {
        owner = msg.sender;

        emit ContractCreated();
    }
}

truffle-test:

const { expectEvent } = require('@openzeppelin/test-helpers');

const TestContract = artifacts.require('Test');

contract('Test', function (accounts) {
    const [owner] = accounts;
    const txParams = { from: owner };

    beforeEach(async function () {
        this.testContract = await TestContract.new(txParams);
    });

    describe('construction', function () {
        it('initial state', async function () {
            expect(await this.testContract.owner()).to.equal(owner);

            await expectEvent.inConstruction(this.testContract, 'ContractCreated');
        });
    });
});

package.json

{
..
  "devDependencies": {
    "@openzeppelin/test-helpers": "^0.5.10"
  }
..
}

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