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
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.
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.)
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.
- 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.
- 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.
- 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,
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
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.
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.
- We do the same thing as previously done, we wait for the contract deployment to be completed.
- 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.
- 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.
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.