To get started, ensure you have Node.js installed. Then, create a new Hardhat project and install the necessary dependencies.

mkdir my-hardhat-project
cd my-hardhat-project
npm init -y
npm install --save-dev hardhat
npx hardhat

Follow the prompts to create a basic sample project. Once your Hardhat environment is set up, you can begin writing tests.

Writing Tests with Hardhat

Hardhat uses Mocha as its testing framework and Chai for assertions. Tests are typically located in the test directory. Below is an example of a simple Solidity smart contract and its corresponding test.

Sample Smart Contract

Create a file named SimpleStorage.sol in the contracts directory:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SimpleStorage {
    uint256 private storedData;

    function set(uint256 x) public {
        storedData = x;
    }

    function get() public view returns (uint256) {
        return storedData;
    }
}

Writing Tests

Now, create a test file named SimpleStorage.test.js in the test directory:

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

describe("SimpleStorage", function () {
    let SimpleStorage;
    let simpleStorage;

    beforeEach(async function () {
        SimpleStorage = await ethers.getContractFactory("SimpleStorage");
        simpleStorage = await SimpleStorage.deploy();
        await simpleStorage.deployed();
    });

    it("Should set the value correctly", async function () {
        await simpleStorage.set(42);
        expect(await simpleStorage.get()).to.equal(42);
    });

    it("Should return 0 initially", async function () {
        expect(await simpleStorage.get()).to.equal(0);
    });
});

Running Tests

To execute your tests, run the following command in your terminal:

npx hardhat test

You should see output indicating that your tests have passed.

Advanced Testing Techniques

Using Fixtures

Fixtures allow you to set up a specific state for your tests. This is especially useful when you have multiple tests that require the same setup. Here’s how to implement a fixture in your tests:

async function deploySimpleStorage() {
    const SimpleStorage = await ethers.getContractFactory("SimpleStorage");
    const simpleStorage = await SimpleStorage.deploy();
    await simpleStorage.deployed();
    return simpleStorage;
}

describe("SimpleStorage with fixtures", function () {
    let simpleStorage;

    beforeEach(async function () {
        simpleStorage = await deploySimpleStorage();
    });

    it("Should set the value correctly", async function () {
        await simpleStorage.set(100);
        expect(await simpleStorage.get()).to.equal(100);
    });
});

Testing for Reverts

You can also test for expected reverts when certain conditions are not met. For example, if you want to ensure that a function cannot be called with a negative value, you can do the following:

it("Should revert when setting a negative value", async function () {
    await expect(simpleStorage.set(-1)).to.be.revertedWith("revert");
});

Using Hardhat Plugins

Hardhat has a rich ecosystem of plugins that can enhance your testing capabilities. One popular plugin is hardhat-gas-reporter, which provides gas usage reports for your tests.

Installing the Plugin

To install the gas reporter, run:

npm install --save-dev hardhat-gas-reporter

Configuring the Plugin

Add the following configuration to your hardhat.config.js file:

require("hardhat-gas-reporter");

module.exports = {
    gasReporter: {
        enabled: true,
        currency: 'USD',
        gasPrice: 21,
    },
};

Viewing Gas Reports

After running your tests, you will see a gas report in the terminal output, detailing the gas usage of each function call.

Summary of Best Practices

Best PracticeDescription
Use FixturesSet up a consistent state for tests using fixtures.
Test for RevertsEnsure your functions revert under invalid conditions.
Write Descriptive TestsUse clear and descriptive names for your test cases.
Leverage PluginsUtilize Hardhat plugins to enhance testing capabilities.
Keep Tests IsolatedEnsure tests do not depend on each other to avoid flakiness.

By following these practices, you can create a robust testing framework for your Solidity smart contracts using Hardhat.

Learn more with useful resources