美文网首页
Truffle中JS测试小技巧

Truffle中JS测试小技巧

作者: 旧时的荣耀 | 来源:发表于2018-08-06 12:05 被阅读0次

    solidity是以太坊上首选的智能合约开发语言,有很多人都用它进行智能合约的学习与开发;而truffle是以太坊上最流行的开发框架,深受大家的喜爱。

    在开发过程中,不可避免的需要对solidity代码进行测试。因为能够按需定制、灵活、方便的原因,大部分人选择的都是基于JS来书写测试代码,因此以下的小技巧都是基于JS测试中遇到的一些困惑之处,总结一下与大家共勉。

    编码风格的选择: .THENASYNC/AWAIT

    因为异步执行的关系,truffle中的JS测试有两种编码风格:

    1. .then风格
    it("should put 10000 MetaCoin in the first account", function() {
      return MetaCoin.deployed().then(function(instance) {
        return instance.getBalance.call(accounts[0]);
      }).then(function(balance) {
        assert.equal(balance.valueOf(), 10000, "10000 wasn't in the first account");
      });
    });
    
    1. ASYNC/AWAIT风格
    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);
    })
    

    这两种风格其实执行的测试内容都一样,但明显ASYNC/AWAIT风格的更适合书写以及阅读——更有美感;而且,更重要的是,修改测试代码时更不容易出错(亲测使用.then风格修改时非常痛苦),所以强烈推荐使用ASYNC/AWAIT风格来书写测试代码。

    如何测试事件

    事件(event)是solidity中用来与前端进行交互的机制,使用的范围很广。但是作为新手时,对于如何测试事件真的是感觉无从下手。

    参考库合约openzeppelin中关于测试事件的写法:

    function awaitEvent (event, handler) {
        return new Promise((resolve, reject) => {
        function wrappedHandler (...args) {
            Promise.resolve(handler(...args)).then(resolve).catch(reject);
        }
          
        event.watch(wrappedHandler);
        });
    }
    
    it("should emit GotPayed", async () => {
        let instance = await PersonalPayment.new();
            
        let event = instance.GotPayed({});
        let watcher = async function (err, result) {
            event.stopWatching();
            if (err) { throw err; }
            assert.equal(result.args._amount, 10);
        };
        await instance.payPayments([accounts[1]], [10], {value: web3.toWei('11', 'ether')});
        await awaitEvent(event, watcher);
    })
    

    其基本思路还是web3接口中的方法:

    1. 设置好event
    2. 写好处理的watcher函数,在awaitEvent函数中通过Promise来进行异步处理

    不过,在实际的测试中,发现了一份更加精简的方案:

    it("should emit GotPayed", async () => {
        let instance = await PersonalPayment.new();
        await instance.payPayments([accounts[1]], [10], {value: web3.toWei('11', 'ether')});
        let event = await new Promise((resolve, reject) => {
            instance.GotPayed((err, log) => {
                if(!err) {resolve(log);}
            })
        });
        assert.equal(event.args._amount, 10);
    })
    

    思路上是模拟的与前端进行交互的方式,在这里加了一层基于Promise的异步调用即可。可以看出,在实际中逻辑更简单,代码也更加简洁

    如何模拟时间跨度进行测试

    在测试中,有时候需要模拟一段时间跨度来测试代码的逻辑,但是在没有教程的情况下,这一步完全是没有思路。我们先上一个例子,再来解读一下:

    await web3.currentProvider.send({
        jsonrpc: "2.0", 
        method: "evm_increaseTime", 
        params: [10], 
        id: 0
    });
    await web3.currentProvider.send({
        jsonrpc: "2.0", 
        method: "evm_mine", 
        params: [], 
        id: 0
    });
    
    1. 通过web3.currentProvider.send方法执行了两条命令:web3.currentProviderweb3接口中的方法,获取当前的网络provider;而接下来的send()则是发起一次RPC调用,输入的是JSON RPC格式的参数来指明要执行的方法:
      • method: "evm_increaseTime:表示执行的方法
      • params: [10]:表示要执行方法的参数
    2. evm_increaseTimeevm_mine皆是来自于Ganache CLI的特有方法:Ganache CLI是开发框架truffle中内置的个人化区块链组件,主要用于模拟以太坊来方便开发、测试与部署;也是当前我们采用的环境。
      • evm_increaseTime:增加区块时间,是我们模拟时间跨度主要需要的功能
      • evm_mine:强制进行一次区块打包,主要是为了让前面执行evm_increaseTime的动作生效

    在完成这些操作之后,就可以进行正常的测试逻辑了。

    相关文章

      网友评论

          本文标题:Truffle中JS测试小技巧

          本文链接:https://www.haomeiwen.com/subject/vfpbvftx.html