(Part 1) Ethereum Testing - Getting Started With Testing (PT 1)

in #utopian-io7 years ago

Repository

https://github.com/igormuba/EthereumTesting/tree/master/class1

What Will I Learn?

  • Basic JavaScript testing syntax
  • How to write meaningful tests
  • How tests work under the hood

Requirements

  • Internet connection.
  • Code editor.
  • Browser.

Difficulty

  • Intermediary.

Tutorial Contents

Introduction

Testing is a very important part of software development. On the other Ethereum development series, we have covered quite some ground with the theory/syntax classes, and practice on the tutorials series on how to build a decentralized exchange.

But we have not done tests. Testing is equally as important as coding, whatever is the language and the technologies you are coding in. So much that there are jobs dedicated just for testing. That is correct, you can get a high paying job just with testing! The catch is, you need to be a great tester, and you need to understand the code as much as the developers, so you can develop insightful and meaningful tests.

There are two ways of testing:

  1. Black box, which means, test the functionality, as if you were a user. We have done a bit of that on the other tutorials.
  2. White box, on these tests, we test as developers, looking at the code and the subtle details.

The main tool we will use is Truffle framework. You could implement everything from scratch with solc to compile your code, web3 to interact with the contracts, etc... But why do that when Truffle comes with all those tools?

Starting a Truffle project

We have already done that in other tutorials, but in case you don't want to follow them and just get started with testing, here is a quick guide.

First, install Node.js from their website

Then, you will need Truffle and some local Ethereum testing environment. I recommend Ganache.

Talking about Ganache first, you can get it from this page.

As for Truffle, you just need to type on your console:

sudo npm install truffle -g

This will install the framework globally.

Now, create a directory where you want to start the project, and inside the directory:

truffle init

Captura de Tela 20190217 às 17.54.50.png
Note: depending on where you create it or your operating system you will need to do use sudo.

The token contract

The contracts should go inside the contracts folder.
For this test, I will use a simple token contract. The code below does not fit in any standard, has not security and prints infinite tokens, but that is exactly why I want to use it for the tests:

pragma solidity ^0.5.0;

contract token{
//mapping of balances of users
    mapping (address => uint) balances;

//calling this will give 10 tokens for free to the caller
    function generateTokens() public{
        balances[msg.sender]+=10;
    }

//calling this will transfer tokens
//notice this does not have any overflow/underflow check!
    function transfer(address _receiver, uint _amount) public{
        balances[msg.sender]-=_amount;
        balances[_receiver]+=_amount;
    }

//returns the balance of someone
    function getBalance(address _owner)public view returns(uint){
        return balances[_owner];
    }
}

The fact that this contract does not have any underflow verification is why I want to use it to do the testing. You will see soon how does it work.

Now, on the migrations folder create the file 2_initial_migration.js to tell Truffle how to deploy the contract:

//instance of the contract
var Token = artifacts.require("./token.sol");

//exports to Ganache
module.exports = function(deployer) {
  deployer.deploy(Token);
};

Network

The last step before we really get into testing is to start our Ganache local Ethereum network and input the data from it into Truffle.

To do that, assuming you have already installed Ganache, like taught on a previous section, open the software and look for this information:
Captura de Tela 20190217 às 18.09.18.png

On the Truffle project folder, find the file truffle-config.js and uncomment the following:
Captura de Tela 20190217 às 18.10.45.png

Into:

development: {
      host: "127.0.0.1",     
      port: 8545,  // default Ganache port is 7545
      network_id: "*",      
     },

Notice that my Ganache port is 8545, but the default is 7545. Make sure you match the port on the code with the port on Ganache.

Compile

To compile, just type on the console, inside the root of the Truffle project folder:

truffle compile

Captura de Tela 20190217 às 18.13.42.png

The first test

The simples test we can make on this contract is to:

  1. Call the function to give us 10 tokens
  2. Check if we have 10 tokens

The structure of the test looks like this:

//loads the token, just like on the migrations
const Token = artifacts.require("token");

//tests for the contract token
contract("Token", accounts =>{
//The tests go here!
});

Inside the contract, between the brackets, we insert the test cases, called "it".

The first test, then, looks like:

it("should have 10 tokens", ()=>

);

And after the arrow => we deploy the token and execute the functions:

Token.deployed().then(instance=>{
    instance.generateTokens();
    return instance.getBalance(accounts[0]);
}).then(balance =>{
    assert.equal(balance.valueOf(), 10, "10 wasn't in the first account");
})

Sounds scary if you have never done that before. But here is how it works:
Token.deployed() returns the instance of the deployed token. We save the returned instance on instance inside the .then. What the .then does is, it waits for the response of what comes before it.

Here is some didactic code, not used anywhere, just for better understanding:

doSomething().then(returnedVariable=>{
    console.log(returnedVariable);
})

So, let us say doSomething returns a string, that THEN is stored in the returnedVariable, and the code after the arrow is executed under that scope.

So, back to the real code. With

instance.generateTokens();
return instance.getBalance(accounts[0]);

We call the generateTokens function that gives 10 tokens to the caller. Then explicitly returns the balance of the account zero, which by default is the one used to execute the tests.

THEN: the code .then(balance =>{ grabs the returned value and pass to the shop of what comes next saved under the variable called balance.

Inside there, we use a few functions to ensure that the result is as expected. You can read that as:

assert.equal(returned value, expected value, "if test fails, this is the message returned");

Moment of truth

To run the tests, save everything and run on the terminal:

truffle test

This is a rare moment when your tests work. You should see something like:
Captura de Tela 20190217 às 19.04.22.png

But in real life, you are expected to find tons of errors. And that is ok, that is exactly the job of the tester. The more errors you find, the better for you (developers hate testers hehe).

I will edit the test so that it throws an error if the balance is not equal to 20:

assert.equal(balance.valueOf(), 20, "20 wasn't in the first account");

And after saving and running the tests, we get the following error:
Captura de Tela 20190217 às 19.07.17.png

Notice there are two tests on the screenshot above. The one on the upside is the one that worked fine. The one below is the one that failed.

With this test you can also notice something:
The contract states are not saved between runs. So, even though we ran 2 tests, and we gave 10 tokens to the same person twice, the second one failed because the state from the first run was lost after the test finished.

So, you can take from this that deployment and tests are not the same things. You can do very in-depth tests without worrying about "breaking" the contract" because the deployment will be another very different contract with no relation to the ones deployed to test.

Also, notice that testing does use the blockchain.

After running all the tests, my Ganache has used almost 40 blocks!
Captura de Tela 20190217 às 19.10.19.png

So, it makes no sense to do tests on the real Ethereum blockchain. Some contracts can be huge and expensive, like the decentralized exchange I have built on another series, that one can cost up to 20 dollars to deploy! It would cost hundreds, maybe thousands, to test!

So, absolutely, you should test only on local testing environments, both for performance and for saving some gas!

Beneficiaries

This post has as beneficiaries

using the SteemPeak beneficiary tool

Captura de Tela 20190122 às 16.07.11.png

Sort:  

Thank you for your contribution @igormuba.
After reviewing your tutorial, we suggest only one point listed below:

  • We suggest that at the end of your tutorial put a GIF of your work.

Excellent work on developing this tutorial. Thank you and good work.

Looking forward to your upcoming tutorials.

Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, click here.


Need help? Chat with us on Discord.

[utopian-moderator]

Hi, thank you for the suggestion. GIF? How exactly a GIF? I didn't understand exactly the purpose you imagine for that, but I am open to try if I understand better.

Thank you for your work.

Thank you for your review, @portugalcoin! Keep up the good work!

Hi, @igormuba!

You just got a 0.22% upvote from SteemPlus!
To get higher upvotes, earn more SteemPlus Points (SPP). On your Steemit wallet, check your SPP balance and click on "How to earn SPP?" to find out all the ways to earn.
If you're not using SteemPlus yet, please check our last posts in here to see the many ways in which SteemPlus can improve your Steem experience on Steemit and Busy.

Congratulations! Your post has been selected as a daily Steemit truffle! It is listed on rank 7 of all contributions awarded today. You can find the TOP DAILY TRUFFLE PICKS HERE.

I upvoted your contribution because to my mind your post is at least 7 SBD worth and should receive 100 votes. It's now up to the lovely Steemit community to make this come true.

I am TrufflePig, an Artificial Intelligence Bot that helps minnows and content curators using Machine Learning. If you are curious how I select content, you can find an explanation here!

Have a nice day and sincerely yours,
trufflepig
TrufflePig

Hi @igormuba!

Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your post is eligible for our upvote, thanks to our collaboration with @utopian-io!
Feel free to join our @steem-ua Discord server

Hey, @igormuba!

Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Get higher incentives and support Utopian.io!
Simply set @utopian.pay as a 5% (or higher) payout beneficiary on your contribution post (via SteemPlus or Steeditor).

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

Coin Marketplace

STEEM 0.04
TRX 0.33
JST 0.094
BTC 63671.12
ETH 1786.46
USDT 1.00
SBD 0.39