How To: Test A Smart Contract Using The Mocha Testing Framework
In two previous blog posts, we’ve written a smart contract using the Solidity programming language and compiled the smart contract to prepare it for deployment. Now we’ll test the code using the Mocha testing framework.
In addition to Mocha, we’ll use Ganache and Web3. Ganache will provide us with a set of unlocked accounts we will use in our local testing environment. In this case “unlocked” means that there is no need to use a public or private key to access them. Web3 provides libraries which will allow us access to a local or remote Ethereum node. For testing purposes, we’ll be connecting to a local node, also provided by Ganache.
Let’s get started.
In the terminal and within your project, type
npm install --save mocha ganache-cli email@example.com(or whichever is the latest version of web3).
Next, create a
test folder, a sibling of the
contracts folder. Inside of the
test folder, create a file called
Let’s start coding :)
First, require the Mocha assertion library, Ganache and Web3. Notice that we capitalize
Web3. It is a constructor, and we’ll be using an instance of it in our code.
interface and the
bytecode from our
compile.js file that we created in the previous blog post.
provider variable and pass it into our instance of
Web3. This lets
Web3 know where it will be getting account information.
That’s our prep code! Now we need to decide what we’ll be testing and why. As of right now, we have access to unlocked accounts and a connection to a local Ethereum node. Let’s take a look at our smart contract to decide what its behaviors should be.
The contract has two functions which we’ll want to test. Does it set an initial message? Does it set a new message?
For either of these functions to be tested, we need to deploy the contract to the local testing environment.
So in addition to testing the functions, we’ll want to make sure that the contract is deploying in the first place. To test this, we’ll check to see that it has an address.
Let’s start with a
beforeEach() hook. Since we need to deploy an instance of the contract each time we run the tests, we’ll make that happen in the
On line 13 we get a list of all accounts. To do this, we use the
eth (Ethereum) module of the Web3 library. On that module we use the
getAccounts() method. Every action in Web3 is asynchronous and will return a promise. This
accounts variable will return a promise that gets resolved with a list of accounts. We will be using one of those accounts to deploy our contract.
On line 14 we create an instance of our contract, passing in the parsed
interface from our
compile.js file. On line 15 we’re not actually deploying, despite the method’s name. What we’re doing is setting up the contract instance with the data in the form of
compile.js and with the initial string we want to use. We wrap the
arguments value in brackets, because the method can take more than one argument. The
send() method actually deploys the contract. We specify the address the contract is coming from. In this case we’ll use the first of the unlocked accounts provided to us by Ganache
accounts. And we’ll specify the amount of gas to send along to complete the deployment. Remember, we’re using fake gas in a local environment, so let’s use more than enough.
1000000 gas will do.
On lines 18 and 19 we set the
log the accounts.
Let’s add at least one test so that we can see the logged accounts (a
beforeEach() hook will not run without a test).
Remember, we are checking to be sure the contract deploys, so here we are asserting that the contract has an address.
Before we run our test, let’s hop over to our
package.json and in
scripts, replace the current value of
Go to your terminal at the root of your project and type
npm run test.
Your test should pass and you should get a list of the ten unlocked accounts you’ll be using for the rest of your tests!
This is exciting. Let’s finish writing our tests.
We know that a contract has an address, now we’d like to test that the contract has a default message, and that the message can be changed.
“default message” test is relatively simple. On line 28 we reference the
hello contract. We then reference one of the methods on the
hello contract, which we delved into in the previous blog post, and we use the
call() method to invoke the function. We get to use the
call() method for free, sans gas, because we are not updating information on the contract. We assert that the default message will be
"Hey world" because that is what we set in our
Let’s test it.
Woohoo! Two passing tests. Can we make it three?
On line 34 we again reference the
hello contract. This time we access the contract’s
setMessage() method, which requires a new message to be passed in. The
send() method requires an address, which tells us which account is paying the gas for this transaction. Unlike the
call() method the
send() method is modifying the
hello contract, and will cost gas.
Let’s try it.
Our Smart Contract deploys an account, has a default message and changes the message. Tune in next time when we deploy our Smart Contract to a test network.