世界各地的组织正在转向区块链技术,以改善数据存储、安全和管理。这导致需要确保对建立在区块链网络上的应用程序进行彻底测试。
在这篇文章中,我们将讨论区块链测试是怎么回事,包括好处和坏处,区块链测试的类型,阶段,以及一些有用的工具。我们还将使用一些推荐的测试工具创建和测试一个智能合约。
什么是区块链测试?
区块链测试是对区块链的各种功能组件(如智能合约)进行系统评估。与传统的软件测试不同,区块链测试涉及多个组件,如区块、采矿、交易、钱包等,所有这些都需要专门的工具来测试。
区块链测试有助于各种质量阶段的发展,从系统性能到区块链应用程序的安全性。
根据IBM企业架构师Santu Maity的说法,区块链测试的最佳方法包含了整个环境。这包括基于区块链的应用程序,包括移动和网络,与区块链系统的功能组件互动,如API、智能合约和节点。
区块链测试的好处
区块链测试确保参与区块链网络的所有实体都得到了正确的操作验证。因此,它为组织提供了一个安全和功能性的基础设施。
区块链测试有助于交付优质产品,从而改善用户体验。它还可以消除涉及金钱的去中心化系统的缺陷,以防止财务损失。
区块链测试的挑战
最重要的挑战之一是缺乏测试工具。目前,每个区块链框架可用的测试工具很少;因此,使用错误的工具会造成问题。
区块链生态系统的另一个问题是缺乏专业知识。因为区块链技术在科技界仍然相对较新,它还没有在软件开发人员中得到广泛的采用。
然而,另一个挑战是测试策略。区块链测试需要对区块链的工作原理有全面的了解和认识。
区块链网络的安全性也可能是困难的。区块链应用现在正被用于各种经济领域。因此,数据安全对于防止邪恶活动至关重要。
无法提供充分的性能和负载测试,对区块链应用程序在某些条件下的性能了解甚少或一无所知。
区块链测试的类型
以下是人们可以在区块链上进行的测试类型的综合清单:
- 功能测试确定区块链系统的各种功能组件的有效性
- 节点测试有助于对网络上的每个节点进行独立测试,以确保连接无问题
- 性能测试确定系统流量限制,并推荐一个最佳解决方案
- API测试有助于在区块链网络中的应用程序之间进行明确的互动,确保这些应用程序之间的请求和响应是正确操作的。
区块链测试的各个阶段
启动阶段
启动阶段是测试区块链系统的第一个阶段。在这里,测试人员通过分析和理解系统的功能来熟悉系统的生命周期,使他们能够更好地了解所有涉及的组件。产生一个详细的地图,包括所有的系统组件和子组件,以及所有的接口,以便很好地了解系统的整体运作。
设计阶段
在设计阶段,必须测试的系统的关键组件被确定,并为区块链系统量身定制了一个详细的测试策略。这个测试策略描述了系统的测试案例和测试环境规范。
规划阶段
在这个阶段,决定如何进行每一种类型的测试,估计在每个层次上进行多少次测试,以及测试的程度。
如果系统不可用,必须设计出替代的测试策略。设置一个私有区块链进行测试是一种替代性的测试策略。API测试,功能测试,性能测试,安全测试等等都是这些测试的例子。
结果阶段
这是最后一个阶段,其中包括在系统中进行的整体测试的报告。系统性能,低级检查,以及区块,交易和智能合约的验证是在这个阶段必须执行的基本练习。
区块链测试工具
以太坊测试器
Ethereum Tester是一个以太坊测试工具,包括Web3集成、API和智能合约。这使得开发团队可以重新创建一个类似生产的以太坊区块链。
作为一个开源的测试库,它实现起来很简单,并且有可管理的API支持,可以满足各种测试要求。
Ganache
这个工具主要用于本地测试Ethereum合约。它生成了一个区块链模拟,允许任何人测试多个账户。
Exonum TestKit
ExonumTestKit专门测试区块链应用程序的整个服务的活动。我们可以使用该工具进行API测试和交易执行,而不必担心网络操作或共识算法。
Corda测试工具
Corda是一个开源的、基于区块链技术的分布式账本平台。通过内置的测试工具,合约测试、集成测试、流程测试和负载测试都变得更加容易。
Truffle
Truffle是一个区块链测试工具,其功能超越了基本的测试,如与Chai和Mocha合作。它在以太坊开发者中是一个众所周知的名字,因为它确定了惊人的测试功能,如自动合约测试。
Populus
Populus框架包括Ethereum的测试功能,它被很好地整合为一套专注于合同部署测试的属性。这些框架大多是围绕pytest框架建立的,允许其非常简单的实现。
测试一个智能合约
现在让我们进入文章的教程部分。在这里,我们将用Truffle开发和测试一个智能合约样本,现在你已经掌握了区块链测试的基础知识。
在这个例子中,我们将为一家汽车商店创建一个汽车跟踪系统。我们将涵盖以下内容:
- 设置开发环境
- 创建一个Truffle项目
- 编写智能合约
- 编译智能合约
- 迁移智能合约
- 测试智能合约
设置环境
要使用Truffle,你需要在你的电脑上安装以下软件:
- Node.js
- npm
- Git
一旦它们被成功安装,请在你的终端运行以下命令:
npm install -g truffle
上面的命令将在你的电脑上全面安装Truffle。在终端键入 "truffle version "以查看Truffle是否正确安装。
创建一个新的Truffle项目
创建一个新的项目目录,内容如下:
mkdir truffle-project
像这样迁移到你的新项目目录中:
cd truffle-project
然后,初始化Truffle:
truffle init
上述命令将为Truffle生成以下目录结构:
contracts/ ,其中包含智能合约的源代码,用Solidity编写。在这个目录里面,有一个重要的合约,叫做Migrations.sol 。
migrations/ 。智能合约的部署是用迁移系统管理的。它被用来监控智能合约的变化。
test/ 是保存智能合约的测试代码和文件的地方。测试可以用Solidity或JavaScript编写。
truffle-config.js 是Truffle的配置文件,在这里你可以定义你的部署网络,用于部署你的智能合约。
创建一个智能合约
在contracts/ 目录中,创建一个名为Auto.sol 的新文件并添加以下内容:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
contract Purchase {
address[20] public buyers;
}
pragma solidity ^0.8.9; 表示所需的 Solidity 的最低版本。pragma 命令的意思是 "只有编译器关心的额外信息",而圆点符号(^)的意思是 "指示的版本或更高的版本"。
当编写 Solidity 时,必须声明像数组和字符串这样的数据类型。Solidity提供了一个特殊的数据类型,称为地址,它也是一个以20个字节值存储的以太坊地址。这个地址可以用来发送和接收以太币。
在contract Purchase{ 范围内,我们定义了一个名为borrower 的公共变量,其类型为address ,长度为20 ,它是一个以太坊地址的数组。一定要记得在每个语句的结尾处加一个分号(;),以避免出错。
现在让我们创建一个允许用户进行借贷请求的函数。在变量声明下面,添加以下内容:
// buying a car
function buy (uint carId) public returns (uint) {
require(carId >= 0 && carId <= 19);
buyer[carId] = msg.sender;
return carId;
}
根据上面的代码,该函数接受一个整数(uint)参数carId ,并期望返回一个整数作为输出。require() 语句是用来确保carId 在买方数组的范围内。因为 Solidity 中的数组是从零开始索引的,carId 的值必须在零和 19 之间。
如果carId 在这个范围内,那么调用的地址就会被添加到我们的buyer 数组中,这个地址用msg.sender 来表示。然后我们返回所传递的carId 。
接下来我们写一个函数来获取所有的买家,就像这样:
// get all buyers
function getBuyers() public view returns (address[20] memory) {
return buyers;
}
我们将buyer ,作为一个类型address[20] memory ,其中包含变量的数据位置。函数声明中的view ,表示该函数不会改变合约的状态。
编译智能合约
在此之后,我们必须编译我们的Solidity代码,以便Ethereum虚拟机(EVM)能够理解它。
在你项目的根目录下打开终端,并输入以下命令:
truffle compile
上述命令将编译合约文件夹中的所有智能合约,以及创建一个build 目录,该目录包含一个带有artifacts 的合约文件夹。
Artifacts是.json 文件,作为与相应的智能合约进行交互的JavaScript封装器。
迁移智能合约
现在合约已经成功编译,是时候将其迁移到区块链上了。
迁移是一个部署脚本,用于改变你的应用程序的合约的状态,将它们从一个状态转移到另一个状态。
为了在区块链上部署智能合约,我们将首先创建迁移配置文件。这是一个JavaScript文件,处理区块链上智能合约的部署。
然而,为了部署带有迁移的智能合约,我们必须首先获得它们的工件,这些工件是作为Truffle编译命令的结果而产生的。在migration 目录内有一个默认的迁移文件1_initial_migration.js ,它负责处理Migration.sol 文件的部署。
让我们创建我们自己的迁移配置文件,2_deploy_contract.js ,内容如下:
const PurchaseContract = artifacts.require('Purchase');
module.exports = function(deployer) {
deployer.deploy(PurchaseContract);
};
artifacts.require() 方法用于指定用于与区块链互动的智能合约。因为一个源文件可能包含多个合约,我们指定了合约定义的名称而不是.sol 文件的名称。在这种情况下,我们使用Purchase ,而不是Auto 。
然后,迁移被导出为一个带有参数(deployer)的函数。对象deployer ,负责暂存部署的工作。接下来,我们部署PurchaseContract 。
接下来,我们将使用另一个名为Ganache的区块链测试工具,提供一个接口来部署我们的智能合约并进行测试。你可以下载或使用命令行npm i -g ganache-cli 。
如果你使用的是Ubuntu操作系统,你可能会发现运行Ganache应用程序的难度。只需右键点击应用程序文件,进入属性,然后进入权限,勾选允许作为程序执行文件。然后重新运行该程序。
我将在本教程中使用Ganache GUI。运行该应用程序,并选择快速启动。下面的图片将显示在屏幕上。

现在让我们来迁移我们的智能合约。
truffle migrate
迁移成功后,你会看到以下内容。
Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.
Starting migrations...
======================
> Network name: 'ganache'
> Network id: 5777
> Block gas limit: 6721975 (0x6691b7)
1_initial_migration.js
======================
Replacing 'Migrations'
----------------------
> transaction hash: 0x7f4ad90e465b3e6501e8a49f3af1692ba39df66cbb6e014061b9e7e592167c02
> Blocks: 0 Seconds: 0
> contract address: 0x5A61A1989d92Fb349fAcd409Fdc8A4C640853fD9
> block number: 1
> block timestamp: 1636840180
> account: 0x3309Fa70a44a69eB7b7E87038Afa61a1C9dDB31b
> balance: 99.99502316
> gas used: 248842 (0x3cc0a)
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.00497684 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.00497684 ETH
2_deploy_contract.js
====================
Replacing 'Purchase'
--------------------
> transaction hash: 0x039224bded1eec1272e422d79ea146aa0026d13252fa7c495628829dbf7d5e42
> Blocks: 0 Seconds: 0
> contract address: 0xA89fdCd07E195be4555E07025b8613224e312F97
> block number: 3
> block timestamp: 1636840182
> account: 0x3309Fa70a44a69eB7b7E87038Afa61a1C9dDB31b
> balance: 99.98848808
> gas used: 284241 (0x45651)
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.00568482 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.00568482 ETH
Summary
=======
> Total deployments: 2
> Final cost: 0.01066166 ETH
现在回到你的Ganache应用程序。

你会发现当前的区块,之前是0,现在是4。另外,第一个地址开始是100个以太,现在是99.99个以太。这是由于迁移的交易成本造成的。
我们已经成功创建并在本地区块链上部署了我们的智能合约。现在我们可以测试我们的智能合约,以确保它做了它应该做的。
测试智能合约
在Truffle中,有两种测试智能合约的方法。第一种是通过使用Solidity,第二种是通过使用JavaScript。在本教程中,我们将使用JavaScript方法。
在test 目录中,创建一个新的文件purchase.test.js ,并编写以下内容。
const Purchase = artifacts.require("Purchase");
contract("Purchase", (accounts) => {
let purchase;
let expectedBuyer;
before(async () => {
purchase = await Purchase.deployed();
});
describe("get account addresses for every purchase", async () => {
before("buy a car using accounts[0]", async () => {
await purchase.buy(4, { from: accounts[0] });
expectedBuyer = accounts[0];
});
it("can retrieve buyer's address by car id", async () => {
const buyer = await purchase.buyers(4);
assert.equal(buyer, expectedBuyer, "Expected to return buyer's account.");
});
it("can retrieve addresses of every buyers", async () => {
const buyers = await purchase.getBuyers();
assert.equal(buyers[4], expectedBuyer, "Buyer should be included.");
});
});
});
首先,我们使用artifacts.require() 方法来导入我们的Purchase 合同。然后,我们声明一个契约,并传入我们的Purchase 实例作为第一个参数,接着传入一个回调函数作为第二个参数。
回调函数的参数是accounts 。accounts 提供网络的可用账户。我们使用before 来确保ID为4 的所购汽车被分配到第一个账户。
然后我们运行一个测试,看哪个地址购买了ID为4 的汽车。为了比较实际值 (buyer) 和预期值 (expectedBuyer) ,我们使用assert.equal 方法。如果测试失败,错误信息将被打印到控制台。
最后,我们检查它是否返回了所有买家的地址。然后我们检查UD4 的地址是否在返回的买家地址中。
现在我们通过运行以下命令来测试我们的合同。
truffle test
如果测试通过,你应该看到下面类似的结果。
Using network 'test'.
Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.
Contract: Purchase
get account addresses for every purchase
✓ can retrieve buyer's address by car id (102ms)
✓ can retrieve addresses of every buyers (429ms)
2 passing (2s)
结论
随着区块链应用的增长,如果不投资于区块链和区块链测试专业知识,就无法满足提供高质量产品的需要。
区块链测试确保系统中的所有组件都能正常工作,并且所有应用程序都以值得信赖的方式与之互动。