Skip to main content

02. 测试框架和环境搭建

🛠️ 测试工具链介绍

1. Hardhat - 以太坊开发框架

Hardhat 是一个完整的以太坊开发环境,提供了编译、部署、测试等功能。https://v2.hardhat.org/tutorial/final-thoughts

主要特性:

  • 本地区块链网络
  • 智能合约编译
  • 测试运行器
  • 调试工具
  • 插件系统

2. Mocha - 测试运行器

Mocha 是一个灵活的 JavaScript 测试框架,支持同步和异步测试。 这是js中的测试框架 https://mochajs.org/next/getting-started/

主要特性:

  • 支持多种测试风格
  • 异步测试支持
  • 钩子函数 (before, after, beforeEach, afterEach)
  • 测试报告

3. Chai - 断言库

Chai 是一个断言库,提供了多种断言风格。 https://www.chaijs.com/

主要特性:

  • 多种断言风格 (expect, should, assert)
  • 丰富的断言方法
  • 可扩展性

4. Ethers.js - 以太坊 JavaScript API

Ethers.js 是一个完整的以太坊钱包实现和工具库。https://docs.ethers.org/v6/

主要特性:

  • 账户管理
  • 合约交互
  • 交易处理
  • 事件监听

🚀 环境搭建步骤

常用命令

npx hardhat init
npx hardhat --version
npm install --save-dev hardhat
npm i hardhat@2.26.0 // 安装指定版本
npm install --save-dev @nomicfoundation/hardhat-toolbox // 这个才会安装对应的chai,ethers等依赖

npm list ethers // 查看包信息

npx hardhat compile
npx hardhat test

// 启动节点
npx hardhat node
npx hardhat node --hostname 127.0.0.1 --port 8545

配置文件

在hardhat.config.js中导入插件包
require("@nomicfoundation/hardhat-toolbox");

步骤 1: 创建项目目录

mkdir my-contract-project
cd my-contract-project
npm init -y

步骤 2: 安装依赖

# 安装 Hardhat
npm install --save-dev hardhat

# 安装测试相关依赖
npm install --save-dev @nomicfoundation/hardhat-toolbox
npm install --save-dev chai
npm install --save-dev mocha

# 安装 OpenZeppelin 合约(如果需要)
npm install @openzeppelin/contracts

步骤 3: 初始化 Hardhat 项目

npx hardhat init

选择 "Create a JavaScript project",这会自动创建基本的项目结构。

步骤 4: 配置 Hardhat

编辑 hardhat.config.js 文件:

require("@nomicfoundation/hardhat-toolbox");

/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: "0.8.19",
networks: {
hardhat: {
chainId: 31337,
},
},
mocha: {
timeout: 40000,
},
};

步骤 5: 创建项目结构

my-contract-project/
├── contracts/ # 智能合约文件
│ ├── Counter.sol
│ └── Token.sol
├── test/ # 测试文件
│ ├── Counter.js
│ └── Token.js
├── scripts/ # 部署脚本
│ └── deploy.js
├── hardhat.config.js # Hardhat 配置
├── package.json
└── README.md

📝 基本测试文件结构

1. 测试文件模板

const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("Contract Name", function () {
// 测试套件开始

let contract;
let owner;
let user1;
let user2;

beforeEach(async function () {
// 每个测试前执行
[owner, user1, user2] = await ethers.getSigners();
const ContractFactory = await ethers.getContractFactory("ContractName");
contract = await ContractFactory.deploy();
});

describe("Function Name", function () {
it("should work correctly", async function () {
// 测试用例
const result = await contract.someFunction();
expect(result).to.equal(expectedValue);
});
});
});

2. 测试文件命名规范

  • 测试文件应该以 .js 结尾
  • 文件名应该与合约名对应
  • 例如:Counter.solCounter.js

🔧 运行测试

1. 运行所有测试

npx hardhat test

2. 运行特定测试文件

npx hardhat test test/Counter.js

3. 运行特定测试套件

grep 匹配的是测试名字符串,不是函数名,grep 区分大小写,中文测试名也可以 grep

npx hardhat test --grep "Counter"
// grep 支持正则匹配,只跑匹配到的
npx hardhat test test/token/Token.test.ts --grep "Token transfer" // 通过正则匹配

通过only

要想只跑指定的单个测试,或是测试块,直接在it或者describe后加上only

npx hardhat test  //  这里就不用加匹配了


it.only("should transfer tokens", async () => {
...
});

describe.only("Token transfer", function () {
...
});

跑失败的

npx hardhat test --grep "@fail"

it("should revert on overflow @fail", async () => {
...
});

并行跑

npx hardhat test --parallel

指定网络

npx hardhat test test/token/Token.test.ts \
--grep "transfer" \
--network hardhat

4. 运行测试并显示详细输出

npx hardhat test --verbose

5. 运行测试并生成覆盖率报告

npx hardhat coverage

最佳实践

日常调试

npx hardhat test test/xxx.test.ts --grep "目标用例"

单点调试

it.only(...)

CI/提交前

npx hardhat test

📊 测试输出解读

1. 成功测试输出

  Counter
✓ should increment counter (45ms)
✓ should decrement counter (34ms)
✓ should reset counter (23ms)

3 passing (102ms)

2. 失败测试输出

  Counter
✓ should increment counter (45ms)
1) should decrement counter
✓ should reset counter (23ms)

2 passing (68ms)
1 failing

1) Counter
should decrement counter:
AssertionError: expected 0 to equal -1
+ expected - actual
-0
+-1

3. 测试统计信息

|  Solidity and Network Configuration
| Solidity: 0.8.19 · Optim: true · Runs: 200 · viaIR: false
| Block: 0 gas · Limit: 30,000,000 gas

| Methods
| Contract / Method · Min · Max · Avg
| Counter · - · - · 45,000
| increment · 45,000 · 45,000 · 45,000
| decrement · 45,000 · 45,000 · 45,000
| reset · 45,000 · 45,000 · 45,000

🎯 测试环境配置

1. 网络配置

// hardhat.config.js
module.exports = {
solidity: "0.8.19",
networks: {
hardhat: {
chainId: 31337,
// 配置测试账户
accounts: {
mnemonic: "test test test test test test test test test test test test junk",
count: 20,
},
},
localhost: {
url: "http://127.0.0.1:8545",
},
},
};

2. 编译器配置

module.exports = {
solidity: {
version: "0.8.19",
settings: {
optimizer: {
enabled: true,
runs: 200,
},
viaIR: false,
},
},
};

3. Mocha 配置

module.exports = {
// ... 其他配置
mocha: {
timeout: 40000, // 测试超时时间
grep: "", // 运行匹配的测试
bail: false, // 遇到错误时是否停止
},
};

🔍 调试测试

1. 使用 console.log

it("should debug values", async function () {
const value = await contract.getValue();
console.log("Current value:", value.toString());
expect(value).to.equal(100);
});

2. 使用 Hardhat Console

npx hardhat console

在控制台中可以直接与合约交互:

const Contract = await ethers.getContractFactory("Counter");
const contract = await Contract.deploy();
await contract.increment();
const value = await contract.count();
console.log(value.toString());

3. 使用 Hardhat Node

npx hardhat node

这会启动一个本地区块链节点,可以在浏览器中查看。

📚 常用测试命令

1. 编译合约

npx hardhat compile

2. 清理编译文件

npx hardhat clean

3. 验证合约

npx hardhat verify --network mainnet CONTRACT_ADDRESS

4. 运行脚本

npx hardhat run scripts/deploy.js --network localhost

🚨 常见问题和解决方案

1. 测试超时

问题: 测试运行时间过长导致超时

解决方案: 增加超时时间

// hardhat.config.js
module.exports = {
mocha: {
timeout: 60000, // 60秒
},
};

2. 内存不足

问题: 运行大量测试时内存不足

解决方案: 分批运行测试或增加 Node.js 内存限制

node --max-old-space-size=4096 node_modules/.bin/hardhat test

3. 网络连接问题

问题: 无法连接到测试网络

解决方案: 检查网络配置和防火墙设置

📖 总结

本章我们学习了:

  • 测试工具链的组成和特性
  • 如何搭建完整的测试环境
  • 测试文件的基本结构
  • 如何运行和配置测试
  • 如何调试测试问题

在下一章中,我们将学习基本的测试语法和写法,包括如何编写各种类型的测试用例。


🔗 相关链接

📢 Share this article