How to Write Basic Tests

Test Setup

We are going to write tests for a simple counter contract:

Overwrite Counter.sol with this contract:

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

contract Counter {
    uint public count;

    // Function to get the current count
    function get() public view returns (uint) {
        return count;
    }

    // Function to increment count by 1
    function inc() public {
        count += 1;
    }

    // Function to decrement count by 1
    function dec() public {
        // This function will fail if count = 0
        count -= 1;
    }
}

Write test file Counter.t.sol:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/Test.sol";
import "../src/Counter.sol";

contract CounterTest is Test {
    Counter public counter;

    function setUp() public {
        counter = new Counter();
    }

    function testInc() public {
        counter.inc();
        assertEq(counter.count(), 1);
    }
}

Test for error

Let's write a test case that fails. Note that setup() will be executed before executing each test case, so the counter contract in the new test case is brand new. It has nothing to do with the operations we have done in the former test case testInc().

function testFailDec() public {
    counter.dec();
}

This new test case shows "PASS" because the testFail prefix tests for failure. A failed testFail case will pass.

vm.expectRevert

We can also specify expected revert reason in the test case:

function testDecUnderflow() public {
    vm.expectRevert(stdError.arithmeticError);
    counter.dec();
}

In this case we are testing for integer underflow.

Add one more test case:

function testDec() public {
    counter.inc();
    counter.inc();
    counter.dec();
    assertEq(counter.count(), 1);
}

Gas Report

forge test --match-path test/Counter.t.sol --gas-report

Last updated