用 Solidity 写测试用例

Solidity test contracts live alongside Javascript tests as .sol files. When truffle test is run, they will be included as a separate test suite per test contract. These contracts maintain all the benefits of the Javascript tests: namely a clean-room environment per test suite, direct access to your deployed contracts and the ability to import any contract dependency. In addition to these features, Truffle’s Solidity testing framework was built with the following issues in mind:

  • Solidity tests shouldn’t extend from any contract (like a Test contract). This makes your tests as minimal as possible and gives you complete control over the contracts you write.

  • Solidity tests shouldn’t be beholden to any assertion library. Truffle provides a default assertion library for you, but you can change this library at any time to fit your needs.

  • You should be able to run your Solidity tests against any Ethereum client.

Example

Let’s take a look at an example Solidity test before diving too deeply. Here’s the example Solidity test provided for you by truffle unbox metacoin:

import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/MetaCoin.sol";contract TestMetacoin {function testInitialBalanceUsingDeployedContract() {MetaCoin meta = MetaCoin(DeployedAddresses.MetaCoin());uint expected = 10000;Assert.equal(meta.getBalance(tx.origin), expected, "Owner should have 10000 MetaCoin initially");}function testInitialBalanceWithNewMetaCoin() {MetaCoin meta = new MetaCoin();uint expected = 10000;Assert.equal(meta.getBalance(tx.origin), expected, "Owner should have 10000 MetaCoin initially");}
}

This produces the following output:

$ truffle test
Compiling ConvertLib.sol...
Compiling MetaCoin.sol...
Compiling truffle/Assert.sol
Compiling truffle/DeployedAddresses.sol
Compiling ../test/TestMetacoin.sol...TestMetacoin✓ testInitialBalanceUsingDeployedContract (61ms)✓ testInitialBalanceWithNewMetaCoin (69ms)2 passing (3s)

Test structure

To better understand whats happening, let’s discuss things in more detail.

Assertions

Your assertion functions like Assert.equal() are provided to you by the truffle/Assert.sol library. This is the default assertion library, however you can include your own assertion library so long as the library loosely integrates with Truffle’s test runner by triggering the correct assertion events. You can find all available assertion functions in Assert.sol.

Deployed addresses

The addresses of your deployed contracts (i.e., contracts that were deployed as part of your migrations) are available through the truffle/DeployedAddresses.sol library. This is provided by Truffle and is recompiled and relinked before each suite is run to provide your tests with Truffle’s a clean room environment. This library provides functions for all of your deployed contracts, in the form of:

DeployedAddresses.<contract name>();

This will return an address that you can then use to access that contract. See the example test above for usage.

In order to use the deployed contract, you’ll have to import the contract code into your test suite. Notice import "../contracts/MetaCoin.sol"; in the example. This import is relative to the test contract, which exists in the ./test directory, and it goes outside of the test directory in order to find the MetaCoin contract. It then uses that contract to cast the address to the MetaCoin type.

Test contract names

All test contracts must start with Test, using an uppercase T. This distinguishes this contract apart from test helpers and project contracts (i.e., the contracts under test), letting the test runner know which contracts represent test suites.

Test function names

Like test contract names, all test functions must start with test, lowercase. Each test function is executed as a single transaction, in order of appearance in the test file (like your Javascript tests). Assertion functions provided by truffle/Assert.sol trigger events that the test runner evaluates to determine the result of the test. Assertion functions return a boolean representing the outcome of the assertion which you can use to return from the test early to prevent execution errors (as in, errors that Ganache or Truffle Develop will expose).

before / after hooks

You are provided many test hooks, shown in the example below. These hooks are beforeAllbeforeEachafterAll and afterEach, which are the same hooks provided by Mocha in your Javascript tests. You can use these hooks to perform setup and teardown actions before and after each test, or before and after each suite is run. Like test functions, each hook is executed as a single transaction. Note that some complex tests will need to perform a significant amount of setup that might overflow the gas limit of a single transaction; you can get around this limitation by creating many hooks with different suffixes, like in the example below:

import "truffle/Assert.sol";contract TestHooks {uint someValue;function beforeEach() {someValue = 5;}function beforeEachAgain() {someValue += 1;}function testSomeValueIsSix() {uint expected = 6;Assert.equal(someValue, expected, "someValue should have been 6");}
}

This test contract also shows that your test functions and hook functions all share the same contract state. You can setup contract data before the test, use that data during the test, and reset it afterward in preparation for the next one. Note that just like your Javascript tests, your next test function will continue from the state of the previous test function that ran.

Advanced features

Solidity tests come with a few advanced features to let you test specific use cases within Solidity.

Testing for exceptions

You can easily test if your contract should or shouldn’t raise an exception (i.e., for require()/assert()/revert() statements; throw on previous versions of Solidity).

This topic was first written about by guest writer Simon de la Rouviere in his tutorial Testing for Throws in Truffle Solidity Tests. N.B. that the tutorial makes heavy use of exceptions via the deprecated keyword throw, replaced by revert()require(), and assert() starting in Solidity v0.4.13.

Also, since Solidity v0.4.17, a function type member was added to enable you to access a function selector (e.g.: this.f.selector), and so, testing for throws with external calls has been made much easier:

pragma solidity ^0.5.0;import "truffle/Assert.sol";contract TestBytesLib2 {function testThrowFunctions() public {bool r;// We're basically calling our contract externally with a raw call, forwarding all available gas, with // msg.data equal to the throwing function selector that we want to be sure throws and using only the boolean// value associated with the message call's success(r, ) = address(this).call(abi.encodePacked(this.IThrow1.selector));Assert.isFalse(r, "If this is true, something is broken!");(r, ) = address(this).call(abi.encodePacked(this.IThrow2.selector));Assert.isFalse(r, "What?! 1 is equal to 10?");}function IThrow1() public pure {revert("I will throw");}function IThrow2() public pure {require(1 == 10, "I will throw, too!");}
}

Testing ether transactions

You can also test how your contracts react to receiving Ether, and script that interaction within Solidity. To do so, your Solidity test should have a public function that returns a uint, called initialBalance. This can be written directly as a function or a public variable, as shown below. When your test contract is deployed to the network, Truffle will send that amount of Ether from your test account to your test contract. Your test contract can then use that Ether to script Ether interactions within your contract under test. Note that initialBalance is optional and not required.

import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/MyContract.sol";contract TestContract {// Truffle will send the TestContract one Ether after deploying the contract.uint public initialBalance = 1 ether;function testInitialBalanceUsingDeployedContract() {MyContract myContract = MyContract(DeployedAddresses.MyContract());// perform an action which sends value to myContract, then assert.myContract.send(...);}function () {// This will NOT be executed when Ether is sent. \o/}
}

Note that Truffle sends Ether to your test contract in a way that does not execute a fallback function, so you can still use the fallback function within your Solidity tests for advanced test cases.

以太坊:用 Solidity 写测试用例相关推荐

  1. 对于以太坊的Solidity语言介绍

    Solidity是什么 Solidity是一门面向合约的.为实现智能合约而创建的高级编程语言,主要目的是为了在以太坊虚拟机(EVM)上运行 Solidity是静态语言,支持继承.库和复杂的用户定义等特 ...

  2. 区块链游戏项目(战舰游戏)基于layer2区块链技术,使用以太坊的solidity语言, 含全栈完整源码

    这里介绍一个基于区块链以太坊开发的战舰游戏项目.做这个项目的初衷是对layer2区块链技术的proof-of-concept.因此,本项目是一个可以在每一个人的电脑上面执行的demo.为了让大家也能执 ...

  3. 教程 | 以太坊智能合约编程之菜鸟教程

    教程 | 以太坊智能合约编程之菜鸟教程 译注:原文首发于ConsenSys开发者博客,原作者为Eva以及ConsenSys的开发团队.如果您想要获取更多及时信息,可以访问ConsenSys首页点击左下 ...

  4. 以太坊智能合约编程之带菜鸟入门教程

    手把手带你走上智能合约编程之路 译注:原文首发于ConsenSys开发者博客,原作者为Eva以及ConsenSys的开发团队.如果您想要获取更多及时信息,可以访问ConsenSys首页点击左下角New ...

  5. 以太坊智能合约编程之菜鸟教程

    手把手带你走上智能合约编程之路 译注:原文首发于ConsenSys开发者博客,原作者为Eva以及ConsenSys的开发团队.如果您想要获取更多及时信息,可以访问ConsenSys首页点击左下角New ...

  6. 以太坊智能合约编程简单教程(全)

    有些人说以太坊太难对付,于是我们(译注:指Consensys, 下同)写了这篇文章来帮助大家学习如何利用以太坊编写智能合约和应用.这里所用到的工具,钱包,应用程序以及整个生态系统仍处于开发状态,它们将 ...

  7. 以太坊是什么,为什么这么火?

    链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. 以太坊是什么 以太坊(Ethereum)是一个建立在区块链技术之上, 去中心化应用平台.它允许任何人在平台中建立和使用通 ...

  8. 【以太坊】在测试网络上发布智能合约

    一.准备工作 1.本地测试网络搭建完成,对以太坊的了解已经达到基础水平.(可以参考我之前的关于以太坊的文章). 2.有翻墙的能力(发布合约的时候,有不少网站都是需要翻墙操作的) 3.本地浏览器安装Me ...

  9. 三天竟然爆发两起大漏洞事件!我们来教你如何跳过以太坊的坑

    三天竟然爆发两起大漏洞事件!我们来教你如何跳过以太坊的坑 2018年04月26日 00:00:00 阅读数:1314 "现在进入你还是先行者,最后观望者进场才是韭菜."美图董事长蔡 ...

  10. 如何通过构建以太坊智能合约来销售商品

    如何通过构建以太坊智能合约来销售商品?这是个问题. 毫无疑问,比特币已经改变了我们看待和理解什么是金钱,价值以及最近由智能合约产生的所有权的方式.这很有趣,因为几乎每个人都听说过它或加密货币.来自许多 ...

最新文章

  1. 在监视器(Monitor)内部,是如何做线程同步的?程序应该做哪种级别的同步?
  2. OpenWrite 公开内测,做最懂你的技术自媒体管理平台!
  3. var和function谁先优先执行_变量var声明和函数function声明优先级
  4. 智慧数字门店管理系统、PAD、门店系统、收银开单、预约服务、会员管理、账单管理、数据统计、商品、库存、美容美体、美甲美睫、医疗美容、美发造型、医疗诊所、中医理疗、宠物服务、美业、经营业务、售卡、交班
  5. 程序设计实践(评注版) 评注者序
  6. arm开发板放张图片动起来_Python与Zynq的桥梁,米尔PYNQ开发板来了
  7. c语言代码行数统计标准,Shell脚本实现C语言代码行数统计
  8. 数据库工程师基础学习1----计算机硬件基础知识,计算机体系结构与存储系统
  9. html页面布局实例,div布局实例
  10. 黑塞矩阵-二阶偏导矩阵
  11. https://www.i5seo.com/
  12. 【电脑技巧】CPU正常运行时间过长,怎么解决?
  13. mysql基于ssm的自习室座位管理系统 毕业设计源码221118
  14. Linux系统编程笔记(李慧琴) 2
  15. 数据结构实验三 用栈实现进制转换和计算器
  16. 2021年中国高粱种植及生产情况分析:内蒙古种植面积及产量均遥遥领先[图]
  17. 阿龙的学习笔记---ElasticSeach的学习与记录
  18. 最全ASCII对应码表-键值
  19. sml基本语法(一)
  20. 摄像头通过服务器和显示器连接,网络摄像头能直接和显示器接吗

热门文章

  1. 差分探头和隔离探头有什么区别
  2. 2020 年 AIoT 产业概述
  3. matlab仿真AMI码变换,matlab编程
  4. [BScroll warn]: Can not resolve the wrapperDOM. .......
  5. 计算机网络实验二局域网络搭建,计算机网络实验二简单共享局域网组建.doc
  6. 带通滤波器作用和用途_带通滤波器是什么,带通滤波器的作用
  7. 把一个base64编码的图片绘制到canvas (canvas的图片在转成dataurl)
  8. 键盘常用ASCII码对照表
  9. mysql nutch_nutch2.2+mysql部署
  10. 微机原理与接口技术实验