Smart Contract Testing & Ethereum Simulator

Amazingandyyy
Aug 5, 2017 · 7 min read

In my last tutorial, I show Solidity programming language a bit and what it feels like to develop a simple HelloWorld smart contract. Today, I am talking about testing which is an important topic in development, especially for the smart contract development.

All codes in this tutorial are available in this repo


Two specific facts in smart contract development that you need to know before I jump in to today’s topic.

  1. Solidity doesn’t natively support logging functions such as console.log() function in Javascript/NodeJS or print() function in python.
  2. The smart contract is executed by Ethereum virtual machine(EVM), so we always need a node or a piece of the Ethereum network to execute the contract. With that been said, you cannot execute a contract in an intuitive manner locally like you did with node, golang, or others.
$ node ./filename.js  -> okay for nodejs
$ go ./filename.go -> okay for golang
$ solc ./contract.sol -> not okay for solidity

I hope you can understand the difficulty of logging and executing a smart contract now.


Here are some options to execute your contract.

  1. Deploy the contract to live(the real) Ethereum main network and execute it. Cost about 5 minutes and real money(slow, public(dangerous), $$$) to deploy and execute.
  2. Deploy the contract to testnet (for developers’ usage) Ethereum network and execute it. Cost about 2 minutes to deploy and free ether(slow, public(dangerous), free)
  3. Deploy to an Ethereum network simulator and execute it. Cost about 3 seconds and free(fast, private(nice!!), free)

In a development lifecycle which we usually want to do unlimited deploying, testing, updating… for many times (let’s say, probably 100+ times in an afternoon.). Then option 3 is the best option. And it is what I am sharing with you in this tutorial. (I will teach you about option 1, 2 in the future post).


Preparation

To prepare, please do following commands to download truffle and ethereumjs-testrpc

$ npm i -g truffle ethereumjs-testrpc

download this repo and go to 02-Testing/start

You should see the files like this

.
├── contracts
│ ├── HelloEthSalon.sol
│ └── Migrations.sol
├── migrations
│ └── 1_initial_migration.js
├── test
├── truffle-config.js
└── truffle.js
3 directories, 5 files

and the HelloEthSalon contract should look like this, and this is what we build in the last tutorial.

pragma solidity ^0.4.4;contract HelloEthSalon {
string message = "Hello Ethereum Salon!";
function HelloEthSalon() {
// constructor
}
function GetMessage() returns (string) {
return message;
}
}

Let’s write a testing file in Javascript

Yes, the most popular way to test a Smart Contract is writing a testing file in Javascript (Javascript wins again).

In the HelloEthSalon contract, we have a function GetMessage() that returns a string of Hello Ethereum Salon!. Let’s write a testing file to test if the function will actually do the job.

In the 02-Testingfolder, use truffle create test command to start a testing file.

$ truffle create test HelloEthSalon

As you can see, the new folder structure should like this:

.
├── contracts
│ ├── HelloEthSalon.sol
│ └── Migrations.sol
├── migrations
│ └── 1_initial_migration.js
├── test
│ └── hello_eth_salon.js
├── truffle-config.js
└── truffle.js
5 directories, 8 files

Hope you notice that we have a new file called hello_eth_salon.js under the test folder. The file looks like following,

contract('HelloEthSalon', function(accounts) {
it("should assert true", function(done) {
var hello_eth_salon = HelloEthSalon.deployed();
assert.isTrue(true);
done();
});
});

Here, we thanks truffle for two things:

  1. It smartly helps us naming the testing file as hello_eth_salon.js when we call the contract HelloEthSalon .
  2. This testing file looks like Mocha-style testing. Yes, we are using Mocha under the hood for smart contract testing.

If you want, I recommend you to split your editor to two sessions. One with the contract itself and other is for writing test file.

Let’s write the testing file as below,

var HelloEthSalon = artifacts.require('./HelloEthSalon.sol');contract(‘HelloEthSalon:GetMessage’, function(accounts) {  it(“should return a correct string”, function(done) {    var hello_eth_salon = HelloEthSalon.deployed();    hello_eth_salon.then(function(contract){      return contract.GetMessage.call(); // **IMPORTANT    }).then(function(result){      assert.isTrue(result === ‘Hello Ethereum Salon!’);      done();    })  });});

here are four important points to check:

  1. don’t forget to import the contract from ‘./HelloEthSalon.sol’ in the first line.
  2. HelloEthSalon.deployed() is a Promise; please help yourself familiar with Promise, because you will use promise a lot in smart contract development since interacting with Ethereum network is always an async behavior, which mean data will come back at some point later.
  3. In line 7, I have an important notes, please remember to use contract.GetMessage.call(); instead usingcontract.GetMessage(); directly
  4. The assertion statement assert.isTrue(result === ‘Hello Ethereum Salon!’); is checking if the result we get from contract.GetMessage.call(); is equal to a string of Hello Ethereum Salon!.

Next, do the truffle test command in the 02-Testing folder,

$ truffle test ./test/hello_eth_salon.js

What did you see? Here we go, we got a really normal/typical error!

Could not connect to your Ethereum client. Please check that your Ethereum client:
- is running
- is accepting RPC connections (i.e., "--rpc" option is used in geth)
- is accessible over the network
- is properly configured in your Truffle configuration file (truffle.js)

We will fix this together in the next session.


Start your Ethereum Simulator

When you do the truffle command, it tries to connect to a Ethereum node, and it, by default, tried to talk a local node on port localhost:8545 by a RPC manner, and notes 8545 is the conventional port for ethereum-node.

Here is some explanation about RPC(Remote procedure call) in case you want to learn more.

In distributed computing, a remote procedure call (RPC) is when a computer program causes a procedure (subroutine) to execute in a different address space (commonly on another computer on a shared network), which is coded as if it were a normal (local) procedure call, without the programmer explicitly coding the details for the remote interaction.

(source: wikipedia)

Eventually, Ethereum just follows the RPC method to have a port that something can talk to. Let’s start a ethereum-rpc on your machine. Just do command testrpc in a new terminal session

$ testrpc

and it will see it starts as normal:

EthereumJS TestRPC v6.0.3 (ganache-core: 2.0.2)Available Accounts
==================
(0) 0x5cc6ee5c4fe0ff63dccb85d5faa802b4e42db244
(1) 0x2442e95edad609c8bf8952384eb1952ec46cc95c
(2) 0xf5f751a7b0fde6b2094bc61bbfe2ec3bc9ed4d80
(3) 0xdf1cf123bdd9871c0973d271045bc5ee138f055a
(4) 0x7a98259c8cb95b4f10e4425a44a2e5d3240b04a9
(5) 0xa1901a3f5f97615494b4605eb22a651de6dc00d8
(6) 0x2d0ada820168741f46ba15140da45d1f0e114296
(7) 0x5a8f3babe912170323b8f9bd725f67cfe2d8056a
(8) 0x3bde7be31bc39c4d8ad8d14ed7e23cbc4e92d3bd
(9) 0xaa3ab94e3205bdb32ebd2c0f5bccf240c1026fac
Private Keys
==================
(0) 565fc08465e8678ef34de22ba9d65d71f388992d04b9fc920e4f7bfa4e169639
(1) 86ebfebd22c626bb3d1ddf8c52332bea4b1f6c0ec210a23e7c248296609006ca
(2) 92b48fcae318e01c2fb082216df921c15b13a9d6842a624e269f2a5630ab63c4
(3) 1c053daa96d53e88585319b9ae1245bfcbc95c8fd8795ff470e98042e4537262
(4) de78e74db0a5c8dae8103c5990ccfed38ceb7b564b6ac6a2d478292af66cabea
(5) c66991438d785e225e9d785cd2e51c2e3adcafe50feb8fa77f6c670e32471f22
(6) 00f67f7649f94b73dacef7fd717dd125ff9f0be00762ca4e928d45885df65010
(7) 8407d5e870732f4cbf7d9ee78284db197fa95feffeec317bed294e1827231ffc
(8) 6800704a7ce0651271cb6392a3f477609f3c61abcec72cc0bf6a78e8c07f9b9c
(9) 09e13e69dad0025411039bc4e0e025b7d2b11aa5a46799318f2ae64fada6df42
HD Wallet
==================
Mnemonic: obtain cereal choose inquiry mercy perfect fee leopard owner live mechanic hip
Base HD Path: m/44'/60'/0'/0/{account_index}
Listening on localhost:8545

It will start with some fake accounts and private keys, and available on localhost:8545. If you see the localhost:8545 , congrats, move to next step, if not, message me, I am willing to help.(It should usually work)


Let’s test it.

Again, do the truffle test command in the 02-Testing folder,

$ truffle test ./test/hello_eth_salon.js

First, you see it compile and … and…. Boom, another Error:

Using network 'development'.Contract: HelloEthSalon:GetMessage
1) should return a correct string
> No events were emitted
0 passing (22ms)
1 failing
1) Contract: HelloEthSalon:GetMessage should return a correct string:
Error: HelloEthSalon has not been deployed to detected network (network/artifact mismatch)
at /Users/andy/.nvm/versions/node/v8.5.0/lib/node_modules/truffle/build/cli.bundled.js:318327:17
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)

The Error said HelloEthSalon has not been deployed to detected network (network/artifact mismatch).

Okay, so the thing is that besides starting the testrpc up, we also need to deploy our contract to the just-startedtestrpc Ethereum Simulator. What we need to do is to update our 1_initial_migration.js file under migrations folder. It should be looked

var Migrations = artifacts.require("./Migrations.sol");module.exports = function(deployer) {
deployer.deploy(Migrations);
};

Let’s import our HelloEthSalon contract right after the MetaCoin importing statement and add a new deploy call right after the deployer.deploy(MetaCoin); . The updated deploy javascript file should be this:

If you are done, again, do the truffle test command in the 02-Testing folder

$ truffle test ./test/hello_eth_salon.js

First, you see it compile and do the testing as following:

Using network 'development'.Contract: HelloEthSalon:GetMessage
✓ should return a correct string
1 passing (44ms)

if you see the ✓ checking mark, congrats, we finish your first ever smart contract testing.

In case you need, here is the whole testcase codes:


Let’s change the contract and update the testing case.

Let’s change the message global variable in he HelloEthSalon contract. Change the message to “I know testing of a contract!!”, yes two exclamation points. And deploy it again by truffle deploy command.

$ truffle migrate

And go to update the test case, to check if the message is what we expect.

$ truffle test ./test/hello_eth_salon.js

If you see the ✓ checking mark, congratulations, you now know to build a safer contract by implementing testing.

The new contract should look like

And the updated testing file should look like


If you enjoyed this article, please share with your developer/blockchain friends and claps if this write-up is anyhow inspiring and helpful. Please feel free to comment if you encounter any errors and any feedback will be appreciated.

Etherereum Salon

A Ethereum Blockchain dev. sharing salon

Amazingandyyy

Written by

Write the code, save myself. Share the code, save the world.

Etherereum Salon

A Ethereum Blockchain dev. sharing salon

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade