Testing the Solidity Smart Contract, step-by-step

Truffle comes with a framework to automate tests, based on Mocha.

We will write a javascript test file that accesses our lottery contract, and interacts with it over an Ethereum local test network, that runs every time we run our tests.

First create a new file under the test directory, by right-clicking it, selecting new, and then file.

We will name it lottery.js

At the beginning of our lottery.js test file, we will use the method:
artifacts.require(“ContractName”), this method returns an abstraction of our contract (ABI), that was created in the compilation process.

We assign the object returned by this method to a constant called Lottery, that we can use to interact with the contract.

We then initialize a variable lottery, that we will later assign to an instance of the Lottery contract.

This is a good time, to explain 3 functions generally used when testing with truffle.

Function

What it does

before()

The before function runs before the testing begins and it can be used to set the adequate variables to be used in each test.

contract()

It works as describe() in mocha, and it names and groups a set of tests under a common group. It includes a block of it() functions.

it()

It includes single units of tests, focused on testing specific aspects in a contract.

Back in our test file, we will instantiate our contract, like this:

lottery = await Lottery.new()

This returns a promise, so we need to wrap it in an asynchronous function that allows that.
In this case, we want to make use of the before function, to instantiate the contract before all the tests are run.

Now we want to will create a contract() function named Lottery Tests that will group all the test functions it() under a themed block.

Note that we are also passing an object called accounts.
This is an array of ethereum addresses, generated by Truffle.
We can reference them to interact with our contract.Note that we are also passing an object called accounts.
This is an array of ethereum addresses, generated by Truffle.
We can reference them to interact with our contract.

Note that we are also passing an object called accounts.
This is an array of ethereum addresses, generated by Truffle.
We can reference them to interact with our contract.

  • After creating our testing block, we can begin the creation of our first test.

When writing our contract we created a variable of type address called manager, that would be assigned to the address of the deployer of the contract:

We should test this behavior using the it() function.

First we want to call the instance of our contract and read, the address of the variable manager. To do so we use the syntax <contract_instance> .<public_variable>.call() as such:

When Truffle, deploys a contract, it uses the first address from the accounts array as default.
So the deployer address should be:

We can check if the manager_address and deployer_address are the same, by using the method assert.equal()
This method takes 2 parameters, to be compared for equality, and a third optional string parameter, to be shown in case the test fails.

We can then assert if both addresses are equal to each other:

Our first test should look like this:

  • Another test we should write is one that checks the process of a player entering the lottery.

The new_player to enter will be selected from the 2nd element of the accounts array.

Back in our lottery.sol contract. We created the enter function, that required, the new player, to send more than 0.1 ether to enter the lottery.

Now in our lottery.js test file, we can trigger this function directly sending an object with 2 parameters in it:

  • from: which is the address creating the transaction
  • value: a string representing value in wei
  • Wei is the minimum unit of ether; 1 eth = 1e18 in scientific notation; 0.11 eth = 11e16 we

We then call the players(array of addresses), with a string ‘0’, representing the first object of the array of players.

Finally, we assert that the player variable is equal to new_player:

This is how our new test should look:

  • We could test if the lottery has a balance, now that the player entered the contest.

First, we must find out, what is the address that references our contract in our local-test-ethereum network. We can do it by reading the address property of the instance of our lottery contract.

In order to find out the balance of our lottery contract, we make use of the method web3.eth.getBalance(), and we pass the lottery.address as an attribute.
This method will return a BigNumber, which should be transformed to .toNumber(), to give the balance available in our lottery contract in Wei.

Finally we, use the method web3.toWei(), to calculate the amount of wei equivalent to 0.11 ether. Which we sent with our player from accounts[1] .

We assert that both the balance and the 0.11 Ether in wei are equal.

The test should look like this:

  • We should test that a player cannot call the selectWinner function.

According to our contract, the selectWinner function uses the modifier managerOnly, which restricts any address, but that belonging to the manager, from triggering this function.

To test this, we can trigger this function, using the address from one of the players accounts[1].
When the function runs, the EVM will throw an error. And we will assert for the existence of this error using a try - catch javascript syntax.

The final test looks as such:The final test looks as such:

The final test looks as such:

  • We should test that the manager, can call the selectWinner function.

First we read the current balance of the contract and assign it to the balance variable

We then call the selectWinner function with the address of the manager

We finally assert, that the contract balance is ‘0’

The last test should look like this:

The final lottery.js file, with all the tests included, should be like this:

Running the Tests

While in our terminal, and making sure we are located in our lotteryapp directory, let’s run the next command to start our tests.

$ truffle test

If all the test pass successfully, we should see an output similar to:

Now that these tests have passed, we can be more confident in the deployment of our contract.