【问题标题】:Testing ethereum events directly in solidity with truffle用松露直接测试以太坊事件
【发布时间】:2017-11-03 03:08:52
【问题描述】:

我发现以下问题用于使用 javascript 测试松露中的事件记录:

Test ethereum Event Logs with truffle

但是 truffle 也支持直接在 solidity 中编写测试。但是,我找不到任何有关如何可靠地测试事件记录的文档。有人可以帮我解决这个问题吗?

【问题讨论】:

  • 你可以在测试中使用 Web3。

标签: unit-testing events ethereum solidity smartcontracts


【解决方案1】:

考虑使用 OpenZeppelin 测试助手expectEvent

以构建过程中发出的事件为例:

合同

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

contract Test {
    address public owner;

    event ContractCreated();

    constructor() {
        owner = msg.sender;

        emit ContractCreated();
    }
}

松露测试

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"
  }
..
}

【讨论】:

    【解决方案2】:

    一般说明:

    请注意,智能合约无法访问事件。根据设计,事件只能从智能合约外部访问。它们不直接存储在区块链中。这意味着您将无法以纯粹的可靠性进行测试。

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

    使用松露测试事件有效,只需按照以下步骤操作:

    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

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

    【讨论】:

      【解决方案3】:

      事件是存储在区块链中的日志。要获得事件,您需要观看链。 http://solidity.readthedocs.io/en/develop/contracts.html#events

      Solidity Truffle 测试是合同。而合约只是存储代码的以太坊账户。当该帐户收到交易时,该代码将被执行。以太坊合约无法通过观察链获取事件日志。所以 Solidity 不支持获取事件。 https://github.com/ethereum/wiki/wiki/White-Paper#ethereum-accounts

      【讨论】:

        猜你喜欢
        • 2016-08-06
        • 1970-01-01
        • 2021-07-17
        • 2021-09-15
        • 1970-01-01
        • 2016-02-28
        • 2020-03-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多