0Pricing
Web3 & DApp Development Fundamentals · 课时

编写测试

Mocha 与 Chai

编写测试 是 CoddyKit 上的免费 Web3 & DApp Development Fundamentals 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Web3 & DApp Development Fundamentals 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Web3 & DApp Development Fundamentals 课程共包含 4 节课。

本课时的部分内容尚未翻译,以英文显示。

Why Test Contracts

Smart contracts are immutable once deployed and often hold real value. A single bug can be unrecoverable, so thorough testing is essential.

  • Catch logic errors before deployment.
  • Document expected behavior.
  • Guard against regressions when refactoring.

Mocha and Chai

Hardhat uses Mocha as the test runner and Chai for assertions, both included in the Toolbox.

  • describe groups related tests.
  • it defines a single test case.
  • expect makes assertions about values.

Tests live in the test/ folder.

A First Test File

A basic test imports ethers and Chai, then deploys and checks the contract:

const { expect } = require("chai"); const { ethers } = require("hardhat"); describe("Greeter", function () { it("returns the initial greeting", async function () { const Greeter = await ethers.getContractFactory("Greeter"); const greeter = await Greeter.deploy(); expect(await greeter.greeting()).to.equal("Hello, Hardhat"); }); });
const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("Greeter", function () {
  it("returns the initial greeting", async function () {
    const Greeter = await ethers.getContractFactory("Greeter");
    const greeter = await Greeter.deploy();
    expect(await greeter.greeting()).to.equal("Hello, Hardhat");
  });
});

Running Tests

Run the whole suite with:

npx hardhat test

Hardhat compiles contracts first, spins up a fresh in-process network, and reports passing and failing tests. You can pass a path to run just one file.

npx hardhat test

Async and await

Almost every contract interaction is asynchronous because it talks to the network. Always await deployments and calls:

it("works", async function () { const c = await Factory.deploy(); await c.waitForDeployment(); const value = await c.getValue(); expect(value).to.equal(0); });

Forgetting await is the most common cause of confusing test results.

it("works", async function () {
  const c = await Factory.deploy();
  await c.waitForDeployment();
  const value = await c.getValue();
  expect(value).to.equal(0);
});

Common Chai Matchers

Chai gives expressive matchers for assertions:

  • .to.equal(x) — strict equality.
  • .to.be.true / .to.be.false — booleans.
  • .to.be.gt(n) — greater than.
  • .to.deep.equal([...]) — array/object equality.
expect(await token.balanceOf(user)).to.equal(100);
expect(await token.balanceOf(user)).to.equal(100);

Working with Signers

getSigners returns test accounts you can use as different users:

const [owner, alice, bob] = await ethers.getSigners(); await token.connect(alice).transfer(bob.address, 50);

connect(signer) sends the next call as that account, which is key for testing access control.

const [owner, alice, bob] = await ethers.getSigners();
await token.connect(alice).transfer(bob.address, 50);

BigInt Values

Numbers on-chain are large integers. In ethers v6 they are JavaScript BigInt values. Compare them carefully:

const supply = await token.totalSupply(); expect(supply).to.equal(ethers.parseEther("1000"));

Use parseEther and formatEther to convert between human and on-chain units.

const supply = await token.totalSupply();
expect(supply).to.equal(ethers.parseEther("1000"));

Setup with beforeEach

Use beforeEach to deploy a fresh contract for every test, ensuring isolation:

let token; beforeEach(async function () { const Token = await ethers.getContractFactory("Token"); token = await Token.deploy(); });

Each it then starts from a clean, identical state.

let token;
beforeEach(async function () {
  const Token = await ethers.getContractFactory("Token");
  token = await Token.deploy();
});

Reading Test Output

A green checkmark means the test passed; a red cross with a diff shows what failed. Mocha prints the describe and it labels, so write descriptive names:

  • Good: it("reverts when caller is not owner")
  • Vague: it("test1")

Running a Single Test

While developing you often want to focus on one test. Use Mocha's .only:

it.only("reverts when not owner", async function () { // only this test runs });

You can also run a single file with npx hardhat test test/Token.js. Remember to remove .only before committing.

it.only("reverts when not owner", async function () {
  // only this test runs
});

Quick Check

Test your understanding of writing contract tests.

Recap

You learned to write contract tests.

  • Hardhat uses Mocha (describe/it) and Chai (expect).
  • Tests live in test/ and run with npx hardhat test.
  • Always await async contract calls.
  • getSigners + connect simulate different users.
  • On-chain numbers are BigInt; use parseEther/formatEther and beforeEach for clean setup.

常见问题解答

「编写测试」课时是免费的吗?

是的 — 「编写测试」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Web3 & DApp Development Fundamentals 课程的其余内容,请升级到 CoddyKit PRO。 Web3 & DApp Development Fundamentals 课程共包含 4 节课。

「编写测试」这节课中我会学到什么?

Mocha 与 Chai 你通过在浏览器中直接运行的动手代码来练习 Web3 & DApp Development Fundamentals,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Web3 & DApp Development Fundamentals 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Web3 & DApp Development Fundamentals 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「编写测试」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Web3 & DApp Development Fundamentals 课中编写并运行代码吗?

能。每节 Web3 & DApp Development Fundamentals 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 编写测试
  2. 测试回滚与事件
  3. 覆盖率与 Gas 报告
  4. 测试夹具
← 返回 Web3 & DApp Development Fundamentals