A step-by-step guide on writing and running smart contract test on the local blockchain.

by Kevin Wong


Writing Tests and Interacting with the Smart Contract

Welcome back reader.

Previously, we have learned how to get started with using truffle to migrate your smart contract to a local Ethereum client. Now, we will look into writing some tests for your smart contract and make your smart contract bug free. Or close to it.

Refer to the repository here: https://github.com/wertykevin91/eth-intro-tutorial

Types of Tests

There are 2 kinds of tests available for truffle. One is testing using solidity smart contracts, the other is testing using plain ol’ javascript. Within javascript, you have two format you can write your tests in, which is the .then promise format or the async/await format. This guide will cover using only the async version of the javascript tests for brevity.

Additional Installations

Before we begin, let’s install and additional NPM library to help us handle big numbers better. Install https://www.npmjs.com/package/bignumber.js by using the command

> npm i bignumber.js

This will not work if you did not initialize NPM as mentioned in the first article.

Before We Begin

Restarted your ganache instance? You can append the –reset (truffle migrate –reset) option to the end of the migration to make sure the migration runs smoothly. Alternatively.. You can delete the build folder if reset does not work. Read more here.

Test

We start by creating our file for the test within the test folder.

Feel free to name it whatever you want. Declare the package bignumber and the artifact for our contract.

Next, we will use the contract function to create an environment for our tests.

The contract function redeploys the contract so that our contract starts with a clean slate. Contract also provides us with the accounts that are available. Don’t forget, you can also get the web3 instance that has already been configured in here. (Note: A web3 instance is also available in the migration deployment back in the first article.)

What is a web3 you might ask? Web3 is a Ethereum compatible Javascript API which allows us to interface with the Ethereum blockchain and create wonderful applications.

A quick side note before we continue. The technical ecosystem for Ethereum is ever changing and something new could be outdated within weeks. Even as I was penning this short guide, I had to revise quite a few things because they don’t work/are not compatible with the latest version.

With that out of the way,

Create a test as shown above. The contract abstraction starts deploying the contract before executing the tests within. The it block encapsulates the different assert statements and contract calls and catches exceptions thrown within it. Truffle uses mocha for the tests framework and you can read more about Mocha here.

Let’s run through the content of the it block.

  1. We take the the HelloWorld contract artifact and wait until it is completely deployed. The deployment uses your code from the deploy migration file and is only flagged as deployed once the deploy migration file is fully ran. The deployed function will return an instance of the HelloWorld contract.
  2. Using the HelloWorld contract, we call the value of the variable message*. Note that you’d call a variable just like how you’d call a function. So keep the function names and variable names distinct (Refer to style guide for more information). Refer to the smart contract in the first article to see what the message variable returns.
  3. Finally, we compare the message to the message obtained from the variable call using strictEqual.

* There are 2 kinds of function calls in Ethereum, a call and a transaction. Calls are local invocation of functions that do not cost Ethers and are not broadcasted to the network. Transactions consume Ethers and are broadcasted to the network to be mined by the miners. For a longer version of this tl;dr, read here.

Now to test your code,

>truffle test

You should see that the test is successful. Don’t forget to turn on Ganache before you begin. Feel free to fiddle with the string and let the test fail.

Tests with Numbers

Numbers in javascript, especially large numbers, are a massive pain to work with. Numbers for web3 and Ethereum? Even more so. Fret not, we will explore some numbers related stuff using bignumber.js and hopefully get rid of some of that confusion by the end of this.

Let’s begin by adding a new variable named number below the message variable.

Now, let us add 2 new functions for storing and retrieving our new variable below our constructor.

Constructor and Functions

Constructors are ran when the contract is deployed and functions are ran when invoked. We can see that the getNumber function has an extra modifier view. View specifies that this function does not write to the blockchain and only reads from the variable states within the contract.

Big Numbers

Let’s begin by adding our test into the test file, below the first test.

Here’s a quick rundown of each step in the code.

  1. We do the same thing as previously done, we wait for the contract deployment to be completed.
  2. We create a BigNumber object with our desired value, 18 million. It is a necessity to use BigNumber libraries when interacting with smart contracts. Just for context, a widely used type in solidity is uint256, in which the largest number is 2^256-1. Javascript cannot handle that.
  3. Notice that here, instead of using a call(), we invoke the function directly. This means that this invocation will be mined and stored in the blockchain as a transaction. I also had to convert my BigNumber into a web3 supported BigNumber. The web3 supported BigNumber is considerably more lightweight and is a lot less robust compared to the version of BigNumber that we have manually included. Fret not, web3.utils.toBN can take care of the conversion of the BigNumber to the type that web3 uses.
  4. We retrieve the number from the blockchain by using a call. As you can see, we can either use our newly added function to retrieve the value OR access the public variable directly. Either way it makes no difference. Finally, we compare the string value of the numbers since JS is unable (or to be fair, comparing using string has given me a lot less headaches) to handle the numeric comparison.

Final Words

Before we end it is important to understand that what is shown here is extremely basic knowledge. Experiment boldy. For the next article, we will visit how to do all these things on an Ethereum testnet instead of doing it locally only.