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.

803

We will name it lottery.js

502

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.

629

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

152

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

FunctionWhat 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.

474

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

567

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:

299

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

734

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:

778

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

557

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:

887

Our first test should look like this:

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

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

370

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.

573

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

763
  • 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.

547

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

789

This is how our new test should look:

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

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.

207

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.

815

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.

597

The test should look like this:

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

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.

490

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.

663
787

The final test looks as such:

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

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

749

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

594

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

334

The last test should look like this:

845

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

813

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:

562

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