Testing Your Solidity Smart Contracts
A good practice in the software industry is writing tests for code. The tests needs.
What you will learn
- Where testing your solidity smart contracts fits into an Ethereum application.
- Which assumptions should be tested before a mainnet deployment.
- What to read next when this concept is working.
A good practice in the software industry is writing tests for code. The tests needs to cover the features of your code and assert that everything is working as predicted. As we are writing smart contracts that can deal with money, writing tests is a really important task for us. The Embark Framework offers a pretty rich environment for testing our smart contracts.
We will write our tests in Javascript using the Mocha. To install it just type npm install -g mocha in your terminal.
The same engineering term can describe different protocol rules. Use the protocol-level Bitcoin versus Ethereum guide.
Let’s start writing test for our MDBService contract that we deployed in our previous tutorial. We want to test the functionalities of our contract:
- It’s empty when initialized
- When a user registers, it creates a contract
- We can retrieve a contract made by a user
- A user can’t register more than one time
We will create a new file in the test directory test/MDBService_spec.js . We will import the libraries and tools we need to test our code:
Ethereum calls and Bitcoin spends use different state models. Compare them with Bitcoin transaction structure and confirmation rules.
var assert = require('assert'); var Embark = require('embark'); var EmbarkSpec = Embark.initTests(); var web3 = EmbarkSpec.web3; Following the Mocha syntax we will describe our tests and deploy all of the contracts in our project:
describe("MDBService", function() { before(function(done) { this.timeout(0); EmbarkSpec.deployAll({}, done); }); //Write your tests here }) Our first test will check if when the MDBService , it is really empty:
To compare network design without reducing it to tickers, use the crypto issuance, control, use-case, and risk comparison.
it("Should be empty after deployment", function(done) { MDBService.getNbAccounts(function(err, result) { assert.equal(result.toNumber(), 0); done(); }); }); Then we will check if an account is really created after we call the register function:
it("A user can register an account", function(done) { MDBService.register({gas:900000}, function(err, result) { MDBService.getNbAccounts(function(err, result) { assert.equal(result.toNumber(), 1); done(); }); }); }); Then we test if the contract has a correct address and our method to access the contracts works:
it("Retrieving the account address should be the same and different from 0x0", function(done) { web3.eth.getAccounts(function(err, accounts) { MDBService.getAccount(accounts[0], function(err, accountaddress) { MDBService.getAccountId(0, function(err, accountaddressid) { assert.equal(accountaddress, accountaddressid); assert.notEqual(accountaddress, '0x0000000000000000000000000000000000000000'); done(); }); }); }); }); And finally we’ll unsure one user can’t create multiple accounts:
it("A user can't register more than one account", function(done) { MDBService.register({gas:900000}, function(err, result) { MDBService.getNbAccounts(function(err, result) { assert.equal(result.toNumber(), 1); done(); }); }); }); Even if smart contracts code are by nature pretty short, writing tests is really important to help you identify errors while building an application. It is also important as in smart contracts development, we often re use existing contracts code and it is important to know that your bricks are sane and safe.
To run your tests using Embark Framework, in a terminal type:
embark test Here is our complete test file:
var assert = require('assert'); var Embark = require('embark'); var EmbarkSpec = Embark.initTests(); var web3 = EmbarkSpec.web3; describe("MDBService", function() { before(function(done) { this.timeout(0); EmbarkSpec.deployAll({}, done); }); it("Should be empty after deployment", function(done) { MDBService.getNbAccounts(function(err, result) { assert.equal(result.toNumber(), 0); done(); }); }); it("A user can register an account", function(done) { MDBService.register({gas:900000}, function(err, result) { MDBService.getNbAccounts(function(err, result) { assert.equal(result.toNumber(), 1); done(); }); }); }); it("Retrieving the account address should be the same and different from 0x0", function(done) { web3.eth.getAccounts(function(err, accounts) { MDBService.getAccount(accounts[0], function(err, accountaddress) { MDBService.getAccountId(0, function(err, accountaddressid) { assert.equal(accountaddress, accountaddressid); assert.notEqual(accountaddress, '0x0000000000000000000000000000000000000000'); done(); }); }); }); }); it("A user can't register more than one account", function(done) { MDBService.register({gas:900000}, function(err, result) { MDBService.getNbAccounts(function(err, result) { assert.equal(result.toNumber(), 1); done(); }); }); }); });Turn the example into production evidence
A working demo is the beginning of verification, not the end. Add tests for failure paths, inspect every permission, and record the chain, contract address, compiler, and dependency versions used for the deployment.
Check behavior
Test expected inputs, boundary values, reverts, events, and calls made to other contracts.
Check operations
Plan key storage, monitoring, pause or upgrade authority, and a response if an assumption stops being true.