智能合约单元测试 – 以ERC20令牌合同为例

作者:刘胜阳

原文地址:https://medium.com/taipei-ethereum-meetup/smart-contract-unit-testing-use-erc20-token-contract-as-an-example-d150c2700834

本文约2000字,阅读(观看)需要12分钟

在我们开始之前

像所有人一样,我正在使用松露框架和Testrpc来加速智能合约开发。本文只关注以太坊智能合约测试。因此,我将跳过这里的环境设置和工具安装,只是在开始测试之前总结一些要点。

  1. 我使用的是Ubuntu 16.04 LTS。
  2. 全球安装松露框架。在这篇文章中,我将简单地“初始化”一个项目。
  3. 我选择Testrpc作为我的以太坊客户端。
  4. 我在此链接上使用“样本固定供应令牌合同”的代码。只需在项目中运行“松露创建合同myContract”并复制并粘贴即可。由于样本中的“throw”已被弃用,请将其更改为“revert()”。
  5. 我会用JavaScript编写测试。因为松露使用摩卡测试框架和柴作为断言库,我建议学习他们的基本用法。另外,还需要JavaScript Promise对象的知识。
  6. 了解ERC20令牌标准的六个功能和两个事件。

一些准备

创建一个原始合同并将其命名为FixedSupplyToken.sol。完成代码后,确保ERC20令牌合约中没有编译错误。


$松​​露编译

启动Testrpc。


$ testrpc

你项目中的2_deploy_contracts.js应该看起来像这样或类似的东西。


var Token = artifacts.require(“FixedSupplyToken”);
module.exports = function(部署者){
  deployer.deploy(Token);
};

将ERC20令牌合同部署到Testrpc。


$松​​露迁移

为此合同创建一个测试.js文件。


$松​​露创建测试fixedsupplytoken

然后,您将在项目的测试目录中拥有fixedsupplytoken.js。编辑fixedsupplytoken.js。


var Token = artifacts.require(“FixedSupplyToken”);
合约(’fixedsupplytoken’,function(accounts){
  it(“should assert true”,function(){
    var token;
    return Token.deployed()。then(function(instance){
     token = instance;
     return token.totalSupply.call ();
    })。then(function(result){
     assert.equal(result.toNumber(),1000000,’total supply is wrong’);
    })
  });
});

artifacts.require()方法返回我们可以在测试脚本的其余部分使用的合同抽象。在上面的代码中,我简单地称之为totalSupply函数(没有事务发送)的合约。因为函数返回promise,所以我使用了附加的回调函数。为简单起见,失败回调被省略。当totalSupply完成(异步请求完成)时,调用成功回调。成功回调参数,result,现在是totalSupply函数的返回值。最后,我使用assert.equal来检查相等性。

运行测试。


$松​​露测试./test/fixedsupplytoken.js




我们征服了一个简单的单元测试。之后,我们将使用类似的技巧来完整地贯穿ERC20令牌合同的每个功能。让我们继续fixedsupplytoken.js。

测试每个功能

首先,我想测试balanceOf函数。将下面的代码添加到fixedsupplytoken.js中(之后(…))。


它(“应该返回令牌所有者的平衡”,function(){
  var token;
  return Token.deployed()。然后(函数(实例){
    令牌=实例;
    返回token.balanceOf.call(accounts [0]);
  })。then(function(result){
    assert.equal(result.toNumber(),1000000,’balance is wrong’);
  })
});

这里的代码几乎相同。不同的是我通过账户[0]来调用函数,这意味着我想知道账户余额[0]。帐户[0]是testrpc提供的第一个地址。我们可以通过帐户[1],帐户[2] …访问其他9个地址。因为部署合同的默认地址是accounts [0],并且在部署合同时,发送事务的人将获得所有令牌(请参阅构造函数) 。此函数调用的返回值将再次为1000000。运行测试,你会看到2通过现在。

测试传输功能。


它(“应该传递正确的令牌”,函数(){
  var令牌;
  返回Token.deployed()。然后(函数(实例){
    令牌=实例;
    返回token.transfer(accounts [1],500000);
  })。然后(function(){
    return token.balanceOf.call(accounts [0]);
  })。(function(result){
    assert.equal(result.toNumber(),500000,accounts [0] balance is wrong) );
    返回token.balanceOf.call(accounts [1]);
  })。然后(function(result){
    assert.equal(result.toNumber(),500000,’accounts [1] balance is wrong’);
  })
});

你会看到,我调用传输功能,无需  .CALL。这是因为我想在这里发送交易并对区块链进行永久更改。 .call只需读取并返回数据,不会对区块链进行更改。现在,如果传递函数运行良好,帐户[0]和帐户[1]将有50万。再次运行测试。 现在,我将完全测试转移,批准和允许功能,因为它们需要彼此形成一个完整的目的 – 授予某人权限以特定数量发送自己的令牌。

我假设以上单元测试的变化仍然存在,所以账户[0]和账户[1]现在有50万。


它(“应该给account [1]权限花费account [0]的token”,function(){
  var token;
  return Token.deployed()。then(function(instance){
   token = instance;
   return token.approve (account [1],200000);
  })。then(function(){
   return token.allowance.call(accounts [0],accounts [1]);
  })。then(function(result){
   assert.equal )
   返回token.transferFrom(accounts [0],accounts [2],200000,{from:accounts [1]});
  })。then(function() {
   return token.balanceOf.call(accounts [0]);
  })。then(function(result){
   assert.equal(result.toNumber(),300000,’accounts [0] balance is wrong’);
   return token.balanceOf.call(accounts [1]);
  })。then(function(result){
   assert.equal(result.toNumber(),500000,’accounts [1] balance is wrong’);
   return token.balanceOf.call(accounts [2]);
  })。then (function(result){
   assert.equal(result.toNumber(),200000,’accounts [2] balance is wrong’);
  })
});

在此测试中,帐户[0]授权(批准功能)帐户[1]使用帐户[0]余额转移200,000。然后,调用allowance函数将返回授权花费的令牌数量。应该是20万。目前,账号[1]可以使用账号[0]的令牌,最多只能发送20万次。

调用批准后,我们可以测试transferFrom。为了测试这个,我们应该发送与账户交易[1],因为它是有能力发送的账户[1]。在这个例子中,我从账户[0]转移到帐户[2] 200,000。因此,您将看到token.transferFrom(accounts [0],accounts [2],200000,{from:accounts [1]})。最后一个参数是可指定发送地址的事务对象。在余下的代码中,我正在检查所有的地址余额。运行测试,另一个通过应该显示。

最后,命令行应该是这样的。




我如何测试一个事件?其实我不知道这是不是一个好方法。这是我的方式。你会看到“转移”


它(“应该显示转移事件”,功能(){
  var令牌;
  返回Token.deployed()。然后(功能(实例){
    令牌=实例;
    返回token.transfer(accounts [1],100000);
  }) .then(function(result){
    console.log(result.logs [0] .event)
  })
});




概要

我自己运行了所有的代码,我仍然在学习。如果有一些错误,请让我知道。希望这个谦虚的文章,也是我自己的一个笔记,可以帮助您了解与松露的基本智能合同测试。


文章转载只为分享区块链技术内容,版权归原作者所有,如有侵权请及时与我们取得联系

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享