What I learned from testing complex smart contracts

Kseniya Lifanova
Upstate Interactive
3 min readOct 3, 2018
http://upstate.agency/smart-contracts

In a previous article, we provide a simple guide on how to write unit tests for smart contracts. Luckily, we can use our favorite tools to test smart contracts: the Mocha framework and Chai assertion library.

Personally, I love writing tests. There is something satisfying about seeing those little green check marks in your terminal. However, when you come across a function with 3 modifiers,7 require statements, 3 if statements, and then if statements nested in if statements, things can get tricky. That leads to so many possible combinations that your head starts to spin.

Mapping out your unit tests before writing any code definitely helps. As I mapped out the functions I was working on, I decided to nest my describe statements. This method helped me to keep my tests organized and minimized the amount of code I needed to write.

Let’s see a simplified example.

Rather than writing several long it statements to account for every possible scenario :

describe('buyTokens(_amount)', function () {
it('it should return true if contract has been activated, contract is not paused, when offering period has started, when offering period has not ended', async function () {
// test code
});
it('it should transfer tokens if contract has been activated, contract is not paused, when offering period has started, when offering period has not ended', async function () {
// test code
});
it('it should revert if contract has not been activated, contract is not paused, when offering period has started, when offering period has not ended', async function () {
// test code
});
it('it should revert if contract has been activated, contract is paused, when offering period has started, when offering period has not ended', async function () {
// test code
});
it('it should revert if contract has been activated, contract is not paused, when offering period has not started, when offering period has not ended', async function () {
// test code
});
});

You can use the nesting method :

describe('buyTokens(_amount)', function () {
describe('when the contract is activated', function () {
describe('when the contract is not paused', function () {
describe('when the offering period has started', function () {
describe('when the offering period has not ended', function () {
it('it should return true', async function () {
// test code
});
it('it should transfer tokens', async function () {
// test code
});
});
describe('when the offering period has ended', function () {
it('it should revert', async function () {
// test code
});
});
});
describe('when the offering period has not started', function () {
// further describes or it tests
});
});
describe('when the contract is paused', function () {
// further it tests
});
});
it('it should revert if contract has not been activated', async function () {
// unit test
});
});

I started with addressing modifiers, then require statements, and lastly the if statements. I nested my describe statements until I got the test to pass, and then worked my way out. In the example above, I knew that in order to get the test to pass (effectively returning true and transferring tokens), I needed to set my test up to have the contract activated, not paused, the offering period started and not ended. Once I got down to the level that would pass the test, I worked my way out. The describe statement outside the it should return true and it should transfer tokensfunctions was:

when the offering period has not ended

I added a describe at the same level to address what would happen conversely:

when the offering period has ended

I continued to work my way up each level until I addressed the very first describe function: when the contract is activated, and created a test for when the contract is not activated.

I encourage you to try this method next time you are testing complex smart contracts. Nesting and using the beforeEach function helps to eliminate duplicate code, and helps you stay organized.

How do you structure your tests? Comment below if you have any tips or tricks!

☞ To stay up to date with our work with smart contract development, follow us on Medium and Twitter.

☞ Need help with writing tests? Contact us at team@upstate.agency!

--

--