Unit Testing in Smart Contracts and Why it is Important.

Unit Testing in Smart Contracts and Why it is Important.

Testing smart contracts is a very important measure for improving smart contract security. Smart contracts, unlike traditional softwares, cannot be updated after launching, making it imperative to test extensively before deploying contracts onto mainnet.

A tiny mistake can lead to drastic losses for both users and projects using smart contracts. This is why testing your contract before deployment is very important to avoid these cases.

Unit Testings

There is a range of testing techniques, from simple manual verifications (interacting with our contract in the terminal console) to complex end-to-end setups, all of them useful in their own way.

In smart contract development, unit testing has proven to be very useful. These tests are simple to write and quick to run, and let you add features and fix bugs in your code with confidence and ease. This testing consists of multiple small, focused tests, which each check a small part of your contract for correctness.

They can often be expressed in single sentences, such as 'the admin is able to pause the contract', 'transferring tokens emits an event' or 'non-admins cannot mint new tokens', followed by lines of codes to check if these actions actually happen without issues. An example can be seen below:

// test/Load.test.js
// Add dependencies
const { expect } = require('chai');

// Start test block
describe('Load', function () {
  before(async function () {
    this.Load = await ethers.getContractFactory('Load');
  });

  beforeEach(async function () {
    this.load = await this.Load.deploy();
    await this.load.deployed();
  });

  // Test case
  it('retrieve returns a value previously stored', async function () {
    // Store a value
    await this.load.store(39);

    // Test if the returned value is the same one
    // Note that we need to use strings to compare the 256 bit integers
    expect((await this.load.retrieve()).toString()).to.equal('42');
  });
});

Setting up Testing Environment

To run this test, we need a testing environment. Using mainnet is expensive and testnet can be very slow. So a local blockchain is very useful in this case. Hardhat, an ethereum development environment, has a local blockchain that can be used. You just need to keep it running in your terminal.

Another important component is Chai. Chai is an assertion library that you can pair with javascript testing framework. This where we get keywords like 'expect', and 'assert' for testing.

You create a file named after the contract you want to test. In the example above, Load.sol is the contract we are testing, so our test file will be Load.test.js.

Finally to run this test, we use command 'yarn hardhat test' or 'npx hardhat test'. If it passes we should get this in terminal:

yarn hardhat test

Congratulations! You just successfully ran a unit test.

Wrap up

Now depending on how big your contract file is, you can continue taking it in bits till you take care of everything (advisable), you can also run more complex tests using Openzeppelin Tests Helper zeppelin Tests Helper. This helps you to capture parts of your code that might not get properly tested in unit testing.

There are of course other testing options available. You can check those out and use them to complement your unit testings for a more secured contract.

Now you know what unit testing is and how to go about it. Get testing!!