如何使用 Solidity 和 JavaScript 测试智能合约【译】

这篇文章主要介绍了如何使用 Solidity 和 JavaScript 测试智能合约【译】 ,文中通过代码以及文档配合进行讲解,很详细,它对在座的每个人的研究和工作具有很经典的参考价值。 如果需要,让我们与区块链资料网一起学习。

https://www.interchains.cc/21449.html

如何使用 Solidity 和 JavaScript 测试智能合约【译】是很好的区块链资料,他说明了区块链当中的经典原理,可以给我们提供资料,如何使用 Solidity 和 JavaScript 测试智能合约【译】学习起来其实是很简单的,

不多的几个较为抽象的概念也很容易理解,之所以很多人感觉如何使用 Solidity 和 JavaScript 测试智能合约【译】比较复杂,一方面是因为大多数的文档没有做到由浅入深地讲解,概念上没有注意先后顺序,给读者的理解带来困难

如何使用 Solidity 和 JavaScript 测试智能合约【译】

  • 测试

Truffle 框架支持 Solidity和 JavaScript 编写测试用例,本文介绍了他们的区别与应用场景。

阅读本文需要对区块链blockchain以太坊eth,JavaScript 有所了解。

所有的代码可以在 Github

软件测试的重要性

如果您希望代码按照预期的方式工作,那么软件测试至关重要。

软件测试有两种常规类型:单元测试集成测试

  • 单元测试地关注每个独立的功能。
  • 集成测试重点在于确保代码的多个部分按预期在一起工作。

区块链blockchain软件也不例外。 而且由于不可变性,区块链blockchain应用程序需要更多地强调测试。

区块链blockchain测试

Truffle 开发框架为我们提供了两种测试Solidity智能合约的途径:Solidity测试和JavaScript测试。 问题是,我们应该使用哪个?

答案是都需要。

如何使用 Solidity 和 JavaScript 测试智能合约【译】

Solidity 测试

用Solidity编写智能合约的测试用例让我们可以在区块链blockchain层级进行测试。这种测试用例可以调用合约方法,就像用例部署在区块链blockchain里一样。为了测试智能合约的内部行为,我们可以:

  • 编写Solidity单元测试来检查智能合约函数的返回值以及状态变量的值。
  • 编写Solidity集成测试来检查智能合约之间的交互。这些集成测试可以确保像继承或者依赖注入这样的机制的运行符合预期

JavaScript 测试

我们也需要确保智能合约能够表现出正确的外部行为。为了从区块链blockchain外部测试智能合约,我们在JavaScript测试用例中使用web3.js,就像在 开发DApp时一样。我们需要有信心对DApp前端可以正确调用智能合约。 这方面的测试属于集成测试。

示例项目

项目的网站代码 Github

我们有两个合约: Backgroundand EntryPoint需要测试.

Background 是一个内部合约,DApp前端不会直接和它交互。EntryPoint 则是设计作为供DApp交互的智能合约,在EntryPoint合约会引用Background合约。

合约

Background合约代码如下:

pragma solidity >=0.5.0;  contract Background {     uint[] private values;      function storeValue(uint value) public {         values.push(value);     }      function getValue(uint initial) public view returns(uint) {         return values[initial];     }      function getNumberOfValues() public view returns(uint) {         return values.length;     } }

在上面,我们看到Background合约提供了三个函数:

  • storeValue(uint):存值
  • getValue(uint) :读取值
  • getNumberOfValues():获取值的

这三个合约函数都很简单,因此也很容易进行单元测试。

EntryPoint.sol 合约代码如下:

pragma solidity >=0.5.0;  import "./Background.sol";  contract EntryPoint {     address public backgroundAddress;      constructor(address _background) public{         backgroundAddress = _background;     }      function getBackgroundAddress() public view returns (address) {         return backgroundAddress;     }      function storeTwoValues(uint first, uint second) public {         Background(backgroundAddress).storeValue(first);         Background(backgroundAddress).storeValue(second);     }      function getNumberOfValues() public view returns (uint) {         return Background(backgroundAddress).getNumberOfValues();     } }

EntryPoint合约的构造函数中,使用了 Background 合约的部署地址,并将其存入一个状态变量backgroundAddressEntryPoint合约暴露出三个函数:

  • getBackgroundAddress():返回Background合约的部署地址
  • storeTwoValues(uint, uint):保存两个值
  • getNumberOfValues():返回值的数量

storeTwoValues(uint, uint)函数调用两次Background合约中的函数,因此对这个函数进行独立单元测试比较困难。getNumberOfValues()也有同样的问题,因此这两个函数更适合进行集成测试。

Solidity 测试用例

在 Solidity 测试用例中,我们将为智能合约编写Solidity单元测试用例和集成测试用例。 让我们先从简单一点的单元测试开始。

TestBackground 测试用例如下:

pragma solidity >=0.5.0;  import "truffle/Assert.sol"; import "truffle/DeployedAddresses.sol"; import "../../../contracts/Background.sol";  contract TestBackground {      Background public background;      // 在每个测试函数之前运行     function beforeEach() public {         background = new Background();     }      // Test that it stores a value correctly     function testItStoresAValue() public {         uint value = 5;         background.storeValue(value);         uint result = background.getValue(0);         Assert.equal(result, value, "It should store the correct value");     }      // Test that it gets the correct number of values     function testItGetsCorrectNumberOfValues() public {         background.storeValue(99);         uint newSize = background.getNumberOfValues();         Assert.equal(newSize, 1, "It should increase the size");     }      // Test that it stores multiple values correctly     function testItStoresMultipleValues() public {         for (uint8 i = 0; i < 10; i++) {             uint value = i;             background.storeValue(value);             uint result = background.getValue(i);             Assert.equal(result, value, "It should store the correct value for multiple values");         }     } }

它测试了 Background 合约,确保它:

  • values数组中保存新的值
  • 按索引返回values
  • values数组中保存多个值
  • 返回values数组的大小

下面是 TestEntryPoint, 包含了一个单元测试testItHasCorrectBackground() 用于验证EntryPoint合约的功能符合预期:

pragma solidity >=0.5.0;  import "truffle/Assert.sol"; import "truffle/DeployedAddresses.sol"; import "../../../contracts/Background.sol"; import "../../../contracts/EntryPoint.sol";  contract TestEntryPoint {      // Ensure that dependency injection working correctly     function testItHasCorrectBackground() public {         Background backgroundTest = new Background();         EntryPoint entryPoint = new EntryPoint(address(backgroundTest));         address expected = address(backgroundTest);         address target = entryPoint.getBackgroundAddress();         Assert.equal(target, expected, "It should set the correct background");     }  }

这个函数测试了注入的依赖。如前所述,EntryPoint合约中的其他函数需要与Background合约交互,因此我们没有办法单独测试这些函数,需要在集成测试中进行验证。下面是集成测试的代码:

pragma solidity >=0.5.0;  import "truffle/Assert.sol"; import "truffle/DeployedAddresses.sol"; import "../../../contracts/Background.sol"; import "../../../contracts/EntryPoint.sol";  contract TestIntegrationEntryPoint {      BackgroundTest public backgroundTest;     EntryPoint public entryPoint;      // 在测试用例之前运行     function beforeEach() public {         backgroundTest = new BackgroundTest();         entryPoint = new EntryPoint(address(backgroundTest));     }      // Check that storeTwoValues() works correctly.     // EntryPoint contract should call background.storeValue()     // so we use our mock extension BackgroundTest contract to     // check that the integration workds     function testItStoresTwoValues() public {         uint value1 = 5;         uint value2 = 20;         entryPoint.storeTwoValues(value1, value2);         uint result1 = backgroundTest.values(0);         uint result2 = backgroundTest.values(1);         Assert.equal(result1, value1, "Value 1 should be correct");         Assert.equal(result2, value2, "Value 2 should be correct");     }      // Check that entry point calls our mock extension correctly     // indicating that the integration between contracts is working     function testItCallsGetNumberOfValuesFromBackground() public {         uint result = entryPoint.getNumberOfValues();         Assert.equal(result, 999, "It should call getNumberOfValues");     } }  // Extended from Background because values is private in actual Background // but we're not testing background in this unit test contract BackgroundTest is Background {     uint[] public values;      function storeValue(uint value) public {         values.push(value);     }      function getNumberOfValues() public view returns(uint) {         return 999;     } }

我们可以看到TestIntegrationEntryPoint使用了一个Background的扩展,即定义在第43行的 BackgroundTest,以其作为我们的模拟合约,这可以让我们的测试用例检查EntryPoint 函数是否调用了部署在backgroundAddress地址处的合约。

Javascript 测试文件

用JavaScript编写集成测试来确保合约的外部行为满足预期要求,这样我们就可以基于这些智能合约开发DApp了。

下面是我们的JavaScript测试文件 entryPoint.test.js

const EntryPoint = artifacts.require("./EntryPoint.sol");  require('chai')     .use(require('chai-as-promised'))     .should();  contract("EntryPoint", accounts => {     describe("Storing Values", () => {         it("Stores correctly", async () => {             const entryPoint = await EntryPoint.deployed();              let numberOfValues = await entryPoint.getNumberOfValues();             numberOfValues.toString().should.equal("0");              await entryPoint.storeTwoValues(2,4);             numberOfValues = await entryPoint.getNumberOfValues();             numberOfValues.toString().should.equal("2");         });     }); });

使用EntryPoint合约中的函数,JavaScript测试用例可以将区块链blockchain外部的值通过交易传入智能合约,这是通过调用合约的storeTwoValues(uint,uint) 函数(第15行)实现的。

通过在测试的第12行和第16行调用getNumberOfValues()来检索存储在区块链blockchain中的值的数量,以确保和存储的值一致。

结论

在测试智能合约时,越多越好。 应该不遗余力确保所有可能的执行路径返回预期结果。 将链级Solidity测试用于单元测试和集成测试,并将Javascript测试用于DApp级别的集成测试。

该项目中有些地方可能要编写更多的单元或集成测试,因此,如果您认为可以添加到该项目中,请向代码库 提交 Pull request。

进一步阅读

如果你觉得本文对你用户,下面的文章也可能对你有用:

  • 了解如何使用Truffle将智能合约部署到公共测试网络(英文) .

    这里有一篇中文文章介绍使用Truffle将智能合约部署到公共测试网络 .

  • 确保智能合约免受黑客攻击,了解 可重入攻击和所有者逻辑盗窃攻击以及如何防止它们 .

  • 了解如何正确加载区块链blockchain,以便您的DApp提供出色的用户体验 .

原文链接:https://medium.com/better-programming/how-to-test-ethereum-smart-contracts-35abc8fa199d

部分转自网络,侵权联系删除www.interchains.cchttps://www.interchains.cc/21449.html

区块链毕设网(www.interchains.cc)全网最靠谱的原创区块链毕设代做网站 部分资料来自网络,侵权联系删除! 最全最大的区块链源码站 ! QQ3039046426
区块链知识分享网, 以太坊dapp资源网, 区块链教程, fabric教程下载, 区块链书籍下载, 区块链资料下载, 区块链视频教程下载, 区块链基础教程, 区块链入门教程, 区块链资源 » 如何使用 Solidity 和 JavaScript 测试智能合约【译】

提供最优质的资源集合

立即查看 了解详情