5. 用solidity测试

Solidity 测试合约以文件的形式与 Javascript 测试一起存在。运行时,它们将作为每个测试协定的单独测试套件包含在内。这些合约保留了 Javascript 测试的所有好处:即每个测试套件的洁净室环境、直接访问已部署的合约以及导入任何合约依赖关系的能力。除了这些功能之外,Truffle 的 Solidity 测试框架在构建时还考虑了以下问题:.sol``truffle test

  • Solidity 测试不应从任何合约(如合约)延伸而来。这使您的测试尽可能少,并让您完全控制您编写的合同。Test

  • Solidity 测试不应受制于任何断言库。Truffle 为您提供了一个默认的断言库,但您可以随时更改此库以满足您的需求。

  • 您应该能够针对任何以太坊客户端运行 Solidity 测试。

在深入研究之前,让我们先看一个 Solidity 测试示例。以下是 Solidity 测试示例: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");

}
}

这将生成以下输出:

$ 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)

测试结构

为了更好地理解发生了什么,让我们更详细地讨论一下。

断言

您的断言函数是由库提供给您的。这是默认的断言库,但是您可以包含自己的断言库,只要该库通过触发正确的断言事件与 Truffle 的测试运行程序松散集成即可。您可以在 Assert.sol 中找到所有可用的断言函数。Assert.equal()``truffle/Assert.sol

已部署的地址

已部署的协定(即作为迁移的一部分部署的协定)的地址可通过库获得。这是由 Truffle 提供的,并在运行每个套件之前重新编译和重新链接,以便为您的测试提供 Truffle 的洁净室环境。此库为所有已部署的合约提供函数,其形式为:truffle/DeployedAddresses.sol

DeployedAddresses.();

这将返回一个地址,然后您可以使用该地址访问该协定。有关用法,请参阅上面的示例测试。

为了使用已部署的合约,您必须将合约代码导入到测试套件中。请注意示例中的内容。这个导入是相对于存在于目录中的测试合约的,它进入测试目录之外,以便找到MetaCoin合约。然后,它使用该协定将地址强制转换为类型。import "../contracts/MetaCoin.sol";``./test``MetaCoin

测试协定名称

所有测试协定都必须以 开头,使用大写字母 。这将此协定与测试助手和项目协定(即被测协定)区分开来,让测试运行者知道哪些协定代表测试套件。Test``T

测试函数名称

与测试协定名称一样,所有测试函数都必须以小写字母开头。每个测试函数都作为单个事务执行,按照在测试文件中出现的顺序执行(就像你的 Javascript 测试一样)。由触发器事件提供的断言函数,测试运行程序通过这些事件进行评估以确定测试结果。断言函数返回一个布尔值,表示断言的结果,您可以使用该布尔值提前从测试中返回,以防止执行错误(例如,Ganache 或 Truffle Develop 将暴露的错误)。test``truffle/Assert.sol

钩子前/后钩

为您提供了许多测试挂钩,如下面的示例所示。这些钩子是 、 和 ,它们与 Mocha 在 Javascript 测试中提供的钩子相同。您可以使用这些挂钩在每次测试之前和之后,或者在运行每个套件之前和之后执行设置和拆卸操作。与测试函数一样,每个钩子都作为单个事务执行。请注意,一些复杂的测试将需要执行大量的设置,这些设置可能会超出单个事务的 gas 限制;您可以通过创建许多具有不同后缀的钩子来绕过此限制,如下例所示:beforeAll``beforeEach``afterAll``afterEach

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");

}
}

此测试协定还表明,您的测试函数和挂钩函数都共享相同的协定状态。您可以在测试前设置合约数据,在测试期间使用该数据,然后在测试后重置合约数据,为下一次测试做准备。请注意,就像您的 Javascript 测试一样,您的下一个测试函数将从运行的上一个测试函数的状态继续。

高级功能

Solidity 测试具有一些高级功能,可让您在 Solidity 中测试特定用例。

测试异常

您可以轻松测试您的合约是否应该引发异常(即,对于 // 语句; 在以前版本的 Solidity 上)。require()``assert()``revert()``throw

这个话题最初是由客座作家 Simon de la Rouviere 在他的教程 Testing for Throws in Truffle Solidity Tests 中写的。注意,本教程通过已弃用的关键字大量使用异常,替换为 、 ,并从 Solidity v0.4.13 开始。throw``revert()``require()``assert()

此外,从 Solidity v0.4.17 开始,添加了一个函数类型成员,使您能够访问函数选择器(例如: ),因此,使用外部调用测试抛出变得更加容易:this.f.selector

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!");
}

}

测试以太币交易

您还可以测试您的合约对接收以太币的反应,并在 Solidity 中编写该交互脚本。为此,Solidity 测试应该有一个返回 的公共函数,称为 。这可以直接写成函数或公共变量,如下所示。当您的测试合约部署到网络时,Truffle 会将该数量的以太币从您的测试账户发送到您的测试合约。然后,您的测试合约可以使用该以太币在被测合约中编写以太币交互脚本。请注意,这是可选的,不是必需的。uint``initialBalance``initialBalance

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/
}
}

请注意,Truffle 以执行回退函数的方式将 Ether 发送到您的测试合约,因此您仍然可以在 Solidity 测试中使用回退函数进行高级测试用例。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值