hardhat 3 测试框架选择
Hardhat 3 中有两个选项,要如何选择呢?
先看看它们的区别吧:
主要区别
选项1:Node Test Runner + Viem
- 测试框架:使用 Node.js 内置的 Test Runner(Node.js 18+原生支持)
- 以太坊库:使用 Viem(现代化的以太坊交互库)
选项2:Mocha + Ethers.js
- 测试框架:使用 Mocha(传统的JavaScript测试框架)
- 以太坊库:使用 Ethers.js(经典的以太坊交互库)
相同的目录结构
my-project/
├── contracts/
│ └── Lock.sol
├── scripts/
│ └── deploy.ts
├── test/
│ └── Lock.test.ts
├── hardhat.config.ts
├── package.json
├── tsconfig.json
└── README.md
相同的 Hardhat 指令
两个版本都支持完全相同的 Hardhat 命令:
# 编译合约
npx hardhat compile# 运行测试
npx hardhat test# 部署脚本
npx hardhat run scripts/deploy.ts# 启动本地网络
npx hardhat node# 其他标准指令
npx hardhat help
npx hardhat clean
npx hardhat verify
主要差异总结
相同部分:
- 项目目录结构 ✅
- Hardhat 配置文件结构 ✅
- 所有 CLI 指令 ✅
- Solidity 合约代码 ✅
- package.json 中的脚本命令 ✅
不同部分:
- 测试文件的导入和语法
- 部署脚本的库调用方式
- package.json 中的依赖包(一个用 viem,一个用 ethers)
- hardhat.config.ts 中可能有不同的插件配置
这两个选项本质上提供了相同的开发体验和工作流程,只是在具体的代码实现语法上有差异。
两个选项创建的项目在文件结构上基本相似,但在以下文件中有语法差异:
测试文件语法差异
Node Test Runner + Viem 版本:
// test/Lock.test.ts
import { describe, it } from "node:test";
import { expect } from "chai";
import { viem } from "hardhat";
import { getAddress, parseEther } from "viem";describe("Lock", () => {it("Should deploy with correct unlock time", async () => {const unlockTime = Math.floor(Date.now() / 1000) + 60;const lockedAmount = parseEther("1");const lock = await viem.deployContract("Lock", [unlockTime], {value: lockedAmount,});expect(await lock.read.unlockTime()).to.equal(unlockTime);});
});
Mocha + Ethers.js 版本:
// test/Lock.test.ts
import { expect } from "chai";
import { ethers } from "hardhat";
import { time } from "@nomicfoundation/hardhat-toolbox/network-helpers";describe("Lock", function () {it("Should deploy with correct unlock time", async function () {const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60;const unlockTime = (await time.latest()) + ONE_YEAR_IN_SECS;const lockedAmount = ethers.parseEther("1");const Lock = await ethers.getContractFactory("Lock");const lock = await Lock.deploy(unlockTime, { value: lockedAmount });expect(await lock.unlockTime()).to.equal(unlockTime);});
});
部署脚本差异
Node Test Runner + Viem 版本:
// scripts/deploy.ts
import { viem } from "hardhat";
import { formatEther, parseEther } from "viem";async function main() {const unlockTime = Math.floor(Date.now() / 1000) + 60;const lockedAmount = parseEther("0.001");const lock = await viem.deployContract("Lock", [unlockTime], {value: lockedAmount,});console.log(`Lock deployed to ${lock.address}`);
}
Mocha + Ethers.js 版本:
// scripts/deploy.ts
import { ethers } from "hardhat";async function main() {const currentTimestampInSeconds = Math.round(Date.now() / 1000);const unlockTime = currentTimestampInSeconds + 60;const lockedAmount = ethers.parseEther("0.001");const lock = await ethers.deployContract("Lock", [unlockTime], {value: lockedAmount,});await lock.waitForDeployment();console.log(`Lock deployed to ${await lock.getAddress()}`);
}
选择建议
选择 Node Test Runner + Viem 如果:
- 你想使用更现代的工具栈
- 项目不需要复杂的测试功能
- 你喜欢更轻量级的测试运行器
- 想要更好的TypeScript支持和类型安全
选择 Mocha + Ethers.js 如果:
- 你更熟悉传统的测试框架
- 需要更丰富的测试功能和插件生态
- 团队已经熟悉Ethers.js
- 需要更成熟的生态系统支持
总的来说,两个选项都能完成相同的功能,主要是在开发体验和语法风格上有所不同。