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.sol→Counter.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. 网络连接问题
问题: 无法连接到测试网络
解决方案: 检查网络配置和防火墙设置
📖 总结
本章我们学习了:
- 测试工具链的组成和特性
- 如何搭建完整的测试环境
- 测试文件的基本结构
- 如何运行和配置测试
- 如何调试测试问题
在下一章中,我们将学习基本的测试语法和写法,包括如何编写各种类型的测试用例。