In this chapter, you're going to code some tests for the Voting
contracts that we have created in the previous chapter.
First, we create our “TestVoting.sol” file in the test/
folder, then type pragma
and then the solidity version.
pragma solidity >=0.4.22 <0.8.0;
import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/Voting.sol";
These first two imports are referring to global Truffle files, not a Truffle directory.
Assert.sol
gives us various assertions to using in our tests, so below type truffle/Assert.sol
Then type truffle/DeployedAddresses.sol
. This one will deploy a fresh instance of the contract being tested to the blockchain. In our case, it is Voting.sol
only for now.
Then import "../contracts/Voting.sol"
, which is the smart contract we want you to test.
Then type contract TestVoting
, and then you type the path of the voting contract to be tested.
Now we need to instantiate the Voting
contract to the deployed contract — Voting voting = Voting(DeployedAddresses.Voting())
. This will be used to call the functions inside of Voting
contracts.
Then type uint256 expectedLocationId = 8
. This is the expected voted location for these tests.
Then you type address expectedVotedLocation = address(this)
. This will return the address of the voted location.
So, notice that before we were setting the ID of the location that we are going to test. And now we are just setting what is the address of this location in the blockchain.
contract TestVoting {
Voting voting = Voting(DeployedAddresses.Voting());
uint256 expectedLocationId = 8;
address expectedVotedLocation = address(this);
Now we are going to test if the user can really vote the location with ID 8 and if the returned ID matched. So basically, we are testing the vote function here.
Type function testUserCanVoteLocation()
. It is public
.
Then uint256 returnedId = voting.vote()
, calling the function vote
from the voting contract. And then we set the expectedLocationId
that we are going to use for this test.
Now we need to type Assert.equal
then returnedId
and then expectedLocationId
.
And then the last parameter is going to be the message that we are going to display.
function testUserCanVoteLocation() public {
uint256 returnedId = voting.vote(expectedLocationId);
Assert.equal(
returnedId,
expectedLocationId,
"User was able to vote for the expected location and expectedVotedLocation should match what is returned."
);
}
Here we are just comparing the returnedId
from this function with the expectedLocationId
that is used for the test.
We can also test the retrieval of a single location's vote.
Now we are going to write function testGetVotedLocationAddressByLocationId()
and it is public
again.
In this test, we are going to compare the address in the blockchain of the location that was voted with the one that we are expecting.
Type address location = voting.locations()
and then expectedLocationId
.
So, the location
function is going to return the address in the blockchain for this location ID.
Now we are going to write the assert, Assert.equal()
which will be location
.
Then expectedVotedLocation
that we set in the beginning of the class,
And then the message that we're going to display.
There is an error on this function, but we are going to figure it out when compiling the contract.
Now we need to write the function to test the location address by location ID in the array.
So, write the function testGetVotedLocationAddressByLocationIdInArray()
. This function is public
as well.
Now type address[16]
(which is the number of the bytes) followed by memory locations = voting.getLocations()
(which is going to return the array of the locations).
We need to assert the location address, so Assert.equal()
then ‘locations[]with the
expectedLocationId` in these array locations.
And then expectedVotedLocation
which again is the address that we set in the beginning of the task.
Finally, add the message that we are going to display for these tests.
function testGetVotedLocationAddressByLocationIdInArray() public {
address[16] memory locations = voting.getLocations();
Assert.equal(
locations[expectedLocationId],
expectedVotedLocation,
"Voted location of the expected location should be this contract"
);
}
In this last test we are getting the location in memory rather than in contract storage since the memory attribute means Solidity will temporarily store the value in memory.
Make sure you have Ganache running, go to your terminal and type truffle test
on the root of the project.
When you run the test, Truffle compiles the contracts again, and also the tests.
I mentioned earlier that there was an error in the code within the tutorial video. Truffle shows a compilation error so you can go back and fix things. In this case, it was missing a bracket when closing the function.
Once I fix that, we can go back and run through a full test again, and then it's going to compile again.
And we are going to see another issue, which is the name of the function locations
on the second test.
It was a typo, using “location” instead of “locations”.
// Code intentionally has 2 errors – missing function closing bracket and typo in the address location line
function testGetVotedLocationAddressByLocationId() public {
address location = voting.location(expectedLocationId);
Assert.equal(
location,
expectedVotedLocation,
"Voted Location of the expected location should be this contract"
);
Now I will go back to the terminal and run truffle test
again.
Here’s the complete test code without any errors for you to see it altogether.
pragma solidity >=0.4.22 <0.8.0;
import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/Voting.sol";
contract TestVoting {
Voting voting = Voting(DeployedAddresses.Voting());
uint256 expectedLocationId = 8;
address expectedVotedLocation = address(this);
function testUserCanVoteLocation() public {
uint256 returnedId = voting.vote(expectedLocationId);
Assert.equal(
returnedId,
expectedLocationId,
"User was able to vote for the expected location and expectedVotedLocation should match what is returned."
);
}
function testGetVotedLocationAddressByLocationId() public {
address location = voting.locations(expectedLocationId);
Assert.equal(
location,
expectedVotedLocation,
"Voted Location of the expected location should be this contract"
);
}
function testGetVotedLocationAddressByLocationIdInArray() public {
address[16] memory locations = voting.getLocations();
Assert.equal(
locations[expectedLocationId],
expectedVotedLocation,
"Voted location of the expected location should be this contract"
);
}
}
Hopefully, this time you see the contracts compiled and also the tests.
And then you see the tests that are running.
You also see the name of the test, how long they took to run, and if they passed or not.
Check Ganache and you can see the balance of the account was reduced as we did a transaction.
So here are my contacts. Feel free to drop me a message if you have any feedback or questions.
Thank you, and I hope you enjoyed the course.