Testing is a critical part of the smart contract development process. However, tests can sometimes be slow, especially as your project grows. In this guide, we will explore various strategies to improve the speed of your Hardhat tests, along with sample code and best practices.

1. Use the Hardhat Network

When running tests, always use the Hardhat Network, which is optimized for speed and provides instant transaction confirmations. It can handle multiple transactions in a single block, making it faster than using a public test network.

Running Tests on the Hardhat Network

To run your tests on the Hardhat Network, simply execute:

npx hardhat test

2. Use `beforeEach` Wisely

The beforeEach hook in Mocha is executed before each test case. If you have expensive setup operations, consider whether they need to run before every test or if they can be run once for multiple tests.

Example of Inefficient Use of `beforeEach`

describe("MyContract", function () {
let myContract;

beforeEach(async function () {
myContract = await MyContract.deploy(); // Deploying before each test
await myContract.deployed();
});

it("Test 1", async function () {
// Test logic
});

it("Test 2", async function () {
// Test logic
});
});

Improved Use of `before`

If the state does not need to be reset between tests, use the before hook instead:

describe("MyContract", function () {
let myContract;

before(async function () {
myContract = await MyContract.deploy(); // Deploying once
await myContract.deployed();
});

it("Test 1", async function () {
// Test logic
});

it("Test 2", async function () {
// Test logic
});
});

3. Minimize State Changes

State changes in smart contracts are costly and can slow down tests. Minimize the number of state changes you make in your tests to improve speed.

Example of Excessive State Changes

it("should update state multiple times", async function () {
await myContract.setValue(1);
await myContract.setValue(2);
await myContract.setValue(3); // Multiple state changes
});

Optimized State Changes

Try to batch state changes when possible:

it("should update state once", async function () {
await myContract.batchUpdate([1, 2, 3]); // Single state change
});

4. Use `skip` and `only` Wisely

While developing, you can use the skip and only methods to focus on specific tests. This can significantly reduce the time spent running tests during development.

Example of Using `only`

it.only("should test specific functionality", async function () {
// This test will run, skipping all others
});

5. Parallel Testing with Mocha

Mocha supports parallel test execution, which can significantly speed up your testing process. You can enable parallel execution by using the beforeEach0 flag when running your tests.

Running Tests in Parallel

beforeEach1

Note that not all tests can run in parallel, especially if they modify shared state. Ensure your tests are independent before using this feature.

6. Optimize Gas Usage in Tests

Optimizing gas usage in your contracts can lead to faster tests. Use tools like the Hardhat Gas Reporter to identify gas-heavy functions and refactor them as needed.

Using Hardhat Gas Reporter

beforeEach2

7. Use Mock Contracts

Mock contracts can be used to simulate the behavior of complex dependencies, allowing you to isolate the contract under test and speed up the testing process.

Example of Using Mock Contracts

beforeEach3

Conclusion

Improving the speed of your Hardhat tests is essential for a smooth development experience. By utilizing the Hardhat Network, optimizing the use of hooks, minimizing state changes, leveraging parallel testing, and using mock contracts, you can significantly reduce the time it takes to run your tests. Implementing these strategies will not only enhance your productivity but also lead to a more efficient development workflow.