Академический Документы
Профессиональный Документы
Культура Документы
Introduction
It is very common to write and compile Solidity code manually which is fine for small
projects. However, as our project is growing bigger and bigger, it is good to have an
automatic way of smart contracts development. In addition, testing Solidity code is
crucial to avoid any problematic situation caused by a bug in the smart contract. There
are different frameworks available for taking care of the development process. Truffle is
one of them and is often regarded as the Ethereum Swiss Knife framework as it is a
development environment, testing framework and asset pipeline for Ethereum.
https://medium.com/oli-systems/test-driven-solidity-with-truffle-e4beaa2bd194 1/21
9/4/2019 Test Driven Solidity with Truffle - OLI Systems - Medium
Objectives
This tutorial is aimed to get started with Truffle and write some tests to check the basic
features offered by Solidity.
Prerequisites
1. Download and install node.js
3. Install ganache-cli:
Ganache is a personal and local blockchain for Ethereum development and provides
a very good environment to deploy smart contracts and run tests. Ganache is
available as a desktop application as well as a command line tool. In this tutorial, we
are going to install ganache as a command line tool by running the following
command in the terminal:
$ npm install ganache-cli -g
$ mkdir truffle-demo
$ cd truffle-demo
$ truffle init
https://medium.com/oli-systems/test-driven-solidity-with-truffle-e4beaa2bd194 2/21
9/4/2019 Test Driven Solidity with Truffle - OLI Systems - Medium
1 Downloading...
2 Unpacking...
3 Setting up...
4 Unbox successful. Sweet!
5 Commands:
6 Compile: truffle compile
7 Migrate: truffle migrate
8 Test contracts: truffle test
If we look at the newly created directory, Truffle has created a boilerplate file structure:
1 C:.
2 | truffle-config.js
3 | truffle.js
4 |
5 +---contracts
6 | Migrations.sol
7 |
8 +---migrations
9 | 1_initial_migration.js
10 |
11 \---test
truffle.js
This is the configuration file that contains information such as development network
settings for the project. This file will be used to configure the development network.
truffle-config.js
This is the same file as truffle.js and used in case of windows system run into a
conflict problem while executing the generic Truffle commands. So, in that case, this file
https://medium.com/oli-systems/test-driven-solidity-with-truffle-e4beaa2bd194 3/21
9/4/2019 Test Driven Solidity with Truffle - OLI Systems - Medium
contracts
This folder is a container for all of our smart contracts. Truffle goes to the contracts
folder and looks for the compatible files ( .sol ) to compile while compiling the project.
The folder already contains a Migrations.sol file.
migrations
The configurations for migrating the contract over the network are written in a
JavaScript file. These settings basically define how (for example: in what order) smart
contracts will be deployed over the blockchain. All those migration files will go inside
the migration folder. This folder contains a file 1_initial_migration.js that will deploy
the Migrations.sol contract to the blockchain.
test
All the tests — either written in Solidity or JavaScript — will go to this folder.
In addition, Truffle will create a build folder to hold artifacts of the compiled contracts.
We will see this folder when we run $ truffle compile command but before that, we
need to set up our private network first.
$ ganache-cli
Ganache has created ten accounts with some amount of ether for executing the
development tasks. It also opens the RPC port 8545 at localhost .
1 module.exports = {
2 networks:{
3 development:{
https://medium.com/oli-systems/test-driven-solidity-with-truffle-e4beaa2bd194 5/21
9/4/2019 Test Driven Solidity with Truffle - OLI Systems - Medium
4 host: '127.0.0.1',
5 port: 8545,
6 network_id: '*' // match any netwrok id
7 }
8 }
9 };
On the next lines, host and port parameters of the network are configured.
Line 6 gives a development network that matches any network it connects to.
So far we have initiated our truffle project, set up private network and ganache-cli
running. In order to check if everything is set up correctly, type:
$ truffle test
Compiling .\contracts\Migrations.sol...
0 passing (1ms)
https://medium.com/oli-systems/test-driven-solidity-with-truffle-e4beaa2bd194 6/21
9/4/2019 Test Driven Solidity with Truffle - OLI Systems - Medium
https://medium.com/oli-systems/test-driven-solidity-with-truffle-e4beaa2bd194 7/21
9/4/2019 Test Driven Solidity with Truffle - OLI Systems - Medium
In the contracts folder, Truffle has just created SimpleContract.sol file with the smart
contract boilerplate. Let’s populate this file with a bit of Solidity code:
setter method.
Line 6 uses the constructor function, that means this function will be automatically
executed once when the smart contract is created. In this case, the value of the above
https://medium.com/oli-systems/test-driven-solidity-with-truffle-e4beaa2bd194 8/21
9/4/2019 Test Driven Solidity with Truffle - OLI Systems - Medium
declared variable name will be set to ‘my name’ when the contract is created.
Line 10 is the getter function that will return the value of name. By default, The
compiler automatically creates getter functions for all public state variables.
However, for the sake of understanding, I have just created a getter function here.
Line 14 defines another function to change the value of our name variable.
This is a very simple smart contract with constructor , one getter and one setter
$ truffle compile
This will compile all the smart contracts from the contracts folder and create artifacts
1 Compiling .\contracts\Migrations.sol...
2 Compiling .\contracts\SimpleContract.sol...
3
4 Compilation warnings encountered:
5
6 /D/GitHub/truffle-demo/contracts/SimpleContract.sol:6:3: Warning: No visibility specified. Defau
7 constructor() {
8 ^ (Relevant source part starts here and spans across multiple lines).
9
10 Writing artifacts to .\build\contracts
If we open the contract folder file from the build directory, we can see that these files
are the abstraction of smart contracts and contain the following information:
contract name
https://medium.com/oli-systems/test-driven-solidity-with-truffle-e4beaa2bd194 9/21
9/4/2019 Test Driven Solidity with Truffle - OLI Systems - Medium
ABI (a list of all functions along with their parameter and return values)
bytecode
deployed bytecode
A list of networks onto which the contract has been deployed (once the contract is
deployed)
address of the contract with respect to each network the contract is deployed to
(once the contract is deployed)
These are .json files and act as a JavaScript wrapper to interact with the respective
smart contracts.
Writing Migrations
In order to deploy smart contract over the blockchain, we first need to write the
configurations for migration in a JavaScript file. These files are basically responsible for
staging the deployment tasks of smart contracts over the blockchain. But, to deploy the
smart contracts with migrations we need to access their artifacts which were created as a
result of truffle compile command.
In order to create a migration file, run the following command in the terminal:
If you go to the migrations folder, you will see a JavaScript migration file is created
which is prefixed by a random number and suffixed by a description. This is because the
history of previously run migrations is recorded on the blockchain and truffle migrate
will start execution from the last run migration. The numbered prefixed is required and
is used to record either a migration has been run successfully or not. Open the newly
created file in text editor and change the contents as follows:
3 module.exports = function(deployer) {
4 // Use deployer to state migration tasks.
5 deployer.deploy(SimpleContract);
6 };
In line 1, we are specifying which contract is going to use for interaction using
artifacts.require() method. This method is similar to node.js require method.
However, it will return a contract abstraction that will be used for the rest of the
deployment script. The important thing here is we have to pass the name of the
contract definition and not the name of .sol file. Because a source file may contain
more than one contracts.
After writing the artifacts, make sure that ganache-cli is running in the background and
run:
$ truffle migrate
$ truffle console
$ SimpleContract.at('0x4f5c2b6471915398132b627fad0f3089ea5ddd05');
It will return the complete abstraction of our contract. We can get the ABI of the contract
$
SimpleContract.at('0x4f5c2b6471915398132b627fad0f3089ea5ddd05').abi;
$
SimpleContract.at('0x4f5c2b6471915398132b627fad0f3089ea5ddd05').getNa
me();
now, first run the changeName() function and then run getName() function to see if the
name is changed to the new name or not.
https://medium.com/oli-systems/test-driven-solidity-with-truffle-e4beaa2bd194 12/21
9/4/2019 Test Driven Solidity with Truffle - OLI Systems - Medium
$
SimpleContract.at('0x4f5c2b6471915398132b627fad0f3089ea5ddd05').chang
eName('your name');
$
SimpleContract.at('0x4f5c2b6471915398132b627fad0f3089ea5ddd05').getNa
me();
When you are done playing with your smart contract, type $ .exit to close the console
mode.
4. Writing Tests
In general, smart contract test can be written both in Solidity and JavaScript. In this
tutorial, We will continue with JavaScript using async/await notation.
1. the constructor is successfully executed while creating the contract. This can be
checked if our getter function returns the same value as passed in the constructor .
2. the changeName method is successfully changing the value of the name variable.
Under the hood, Truffle uses Mocha testing framework and Chai assertion library to test
the smart contracts. Furthermore, truffle test command will run the tests from all the
test files inside the test folder.
But even before writing the tests in JavaScript, let’s write a test to test the constructor in
plain English for our getter method:
https://medium.com/oli-systems/test-driven-solidity-with-truffle-e4beaa2bd194 13/21
9/4/2019 Test Driven Solidity with Truffle - OLI Systems - Medium
Open the newly created simple_contract.js file from the test folder and we will find a
basic test sample there. We can see that Truffle is using contract() instead of
describe() as its main function. The contract() provides a list of account available by
the Ethereum client (in our case Ganache) which can be used to write tests.
Furthermore, it also groups together all the tests for a specific contract. Let’s test the
available accounts. Change the contents of your test file as below and run the following
command:
$ truffle test
In line 3, contract() method is used for grouping the tests. It uses a message in
order to understand the purpose of the test.
The actual test starts in line 4, what we are going to test. As a result, we will see a list of
available accounts.
Testing Constructor
Now let’s write the actual test for the constructor :
In line 6, we have created the instance of our contract to access its methods.
In line 7, we are storing the return value of getName() method so that we can check
it out.
In line 9, we are asserting that the value should be equal to ‘my name’.
Now run the $ truffle test command and we will see one test is passing!
Next, we will add another test for our changeName() method. Add the following test at
line 11 below test 1.
In this test we are calling the changeName() method with ‘your name’ and in the next
line, we are storing this value into a variable. Again run the $ truffle test command.
Testing Modifiers
The use of function modifiers in the Solidity is also a common pattern to have a better
control over contract’s methods execution.
https://medium.com/oli-systems/test-driven-solidity-with-truffle-e4beaa2bd194 15/21
9/4/2019 Test Driven Solidity with Truffle - OLI Systems - Medium
Let’s add a modifier onlyOwner() that will restrict the execution of a certain method
only to the owner of the contract.
We have created a private variable owner and assign it to the creator of the contract
using the constructor function.
In line 12, we have declared a function modifier which will check if the caller of the
method is the owner of the contract, then continue ( _; ).
In line 22, the function modifier is assigned to the method changeName() by adding
the name of the modifier.
https://medium.com/oli-systems/test-driven-solidity-with-truffle-e4beaa2bd194 16/21
9/4/2019 Test Driven Solidity with Truffle - OLI Systems - Medium
Open the simple_contract.js file again and add the following test for the modifier. But
before doing that, we will re-arrange the test to make our lives even easier.
Instead of creating the contract instance for every test, we have created a global instance
of the contract using the beforeEach hook provided by Mocha.
As we have put the modifier for changeName() method, now only the owner should be
able to change the name. This test is specified at line 23. If we run the $ truffle test
command again, we see that the test is passed. This is because if we don’t specify the
https://medium.com/oli-systems/test-driven-solidity-with-truffle-e4beaa2bd194 17/21
9/4/2019 Test Driven Solidity with Truffle - OLI Systems - Medium
account, ganache automatically uses the first account. In this case, the owner of the
contract and caller of the method are the same, so why the test is passed. In order to
really check the modifier, let’s use the transaction object in our test:
Use any other account other than the first account ( accounts[0] ) from the list of
available accounts and run the test again. You will see your test is failed now because the
only owner can call this method. Although, using any other account other than the
owner will lead to failing the test but we want our test to pass. This is important, because
although the test is asserting a failing behavior, a test itself should always pass its
assertion. Here comes the idea of revert into play. The truffle-assertions library has
the ability to assert that a transaction reverts as expected. The truffle-assertions
package adds additional assertions that can be used to revert transactions in the smart
contracts.
Also import this package at the top or our test file, just below the liner requiring artifacts
of the contract:
add the following test and run the truffle test command again. At this time our test is
passed with the expected behavior of the contract!
https://medium.com/oli-systems/test-driven-solidity-with-truffle-e4beaa2bd194 18/21
9/4/2019 Test Driven Solidity with Truffle - OLI Systems - Medium
Listening Events
Using the truffle-assertions package that we just installed, we can:
Let’s add a name event that will be fired every time name is changed.
add the following test to check if a specific event is present in the transaction or not and
run the truffle test command:
https://medium.com/oli-systems/test-driven-solidity-with-truffle-e4beaa2bd194 19/21
9/4/2019 Test Driven Solidity with Truffle - OLI Systems - Medium
We are saving the transaction into a result variable and then check that if ‘NameEvent’ is
emitted by the transaction or not.
In the end, we are going to print out the event parameters and their values emitted by a
particular event:
after running the truffle test command, you will see the transaction emitting the event,
name of the emitted event, its parameter, and values.
https://medium.com/oli-systems/test-driven-solidity-with-truffle-e4beaa2bd194 20/21
9/4/2019 Test Driven Solidity with Truffle - OLI Systems - Medium
Related articles
Truffle
Truffle Assertions
Mocha
Chai
https://medium.com/oli-systems/test-driven-solidity-with-truffle-e4beaa2bd194 21/21