What is a blockchain?
A blockchain is a chain of blocks with information stored on it. In the beginning, this technology was specifically designed to timestamp digital documents to prevent them from being backdated or tampered with. However, because this system records information in such a way that it becomes almost impossible to hack, change, or cheat the system, it has become widely accepted as a platform that addresses the current challenges of data breaches in e-commerce.
While the growing popularity of blockchain technology is forcing us to adapt our existing testing strategies, there are however some disadvantages. We discuss these in detail below.
What is blockchain testing?
Blockchain testing is the process of systemic evaluation of the different functional components of the blockchain, for example, smart contracts. Unlike traditional software testing, a number of components are involved in blockchain testing, each of which requires special tools to test: transactions, blocks, mining, wallets, etc.
Blockchain testing assists in the development of the various quality stages which range from system performance to security of the blockchain application.
Enterprise Architect at IBM, Santu Maity, suggests that encompassing the entire environment in blockchain testing is the best approach. This would include both mobile and web blockchain-based applications that interact with the functional component of the blockchain system, for example, smart contracts, nodes, and Application Programming Interface (API).
Advantages of blockchain testing
Blockchain testing ensures the proper validation of all entities participating in a blockchain network. Because of this, it provides a functional and secure infrastructure to organizations.
Blockchain testing helps deliver quality products, which in turn improves user experience. Also, where money is involved, blockchain testing eliminates the shortcomings of a decentralized system to prevent financial damage.
Disadvantages of blockchain testing
The most noteworthy disadvantage of blockchain testing is the shortage of testing tools. Currently, because there are not many testing tools available for each blockchain framework, problems may arise if the wrong tool is used.
Another disadvantage is the lack of professional expertise. This is because blockchain technology is fairly new in the tech world, and its adoption has not been widespread among software developers.
A further disadvantage is the testing strategy. Blockchain testing requires in-depth knowledge and understanding of the way blockchain works.
Another disadvantage is the difficulty that presents with the security of the blockchain network. Because so many different economic sectors use blockchain applications, it is imperative to secure the data in order to prevent criminal activities.
Yet another disadvantage of blockchain testing is its limited ability to perform load and performance testing. Without this, there is little to no insight into the performance of blockchain applications in production and under various conditions.
Types of blockchain testing
Below we provide a comprehensive list of the various types of testing that can be performed on a blockchain:
- Functional testing is a holistic process that determines the effectiveness of various functional parts of the blockchain
- Performance testing identifies the bottlenecks to system performance, recommends adjustments to achieve the desired performance, and assesses the application’s readiness for launching
- API testing addresses the interaction between applications in the complex network of blockchain. It ensures that API requests and responses are properly managed.
- Node testing facilitates independent testing of all heterogeneous nodes on the network and ensures a problem-free connection
Phases of blockchain testing
Initiation phase
This is the first phase of testing a blockchain system. At this stage, the testers familiarize themselves with the system’s lifecycle, its functionality, and all components involved. A map generated here details the system’s components, subcomponents, and interfaces, and their interaction.
Design phase
This phase identifies the key components of the system that need to be tested so that a detailed test strategy customized for the blockchain system can be developed. Details of the system’s test cases and test environment can be found in this test strategy.
Planning phase
The planning phase decides the number of times each test will be performed at each level, and how.
Alternative testing strategies need to be devised in the event that the system is unavailable, for example, the set up of a private blockchain for testing. These would include security testing, functional testing, API testing, and performance testing.
Result phase
Here at the result phase, the final phase of blockchain testing, a number of fundamental exercises need to be performed. These include low-level check, transactions, system performance, validation of blocks, and smart contracts. An overall test report is also included in this phase.
Blockchain testing tools
Exonum TestKit
Exonum TestKit specializes in testing the operation of the complete service of the blockchain application. The tool makes provision for testing API and transaction execution without involving the network operation or consensus algorithm.
Corda testing tool
Corda is a testing framework with an open source blockchain platform that facilitates the development of interoperable blockchain networks that conducts business with strict privacy. With various distinct test suites and each with a different purpose, it simplifies contract testing, flow testing, integration testing, and load testing.
Ethereum tester
Ethereum is one of the most utilized platforms in blockchain application development. It is filled with tools that make application development and testing easier.
Ethereum Tester is reliable for smart contracts, API, backend, Web3 Integration, and various other blockchain tests.
Truffle
Truffle is a blockchain testing tool, well-known among Ethereum developers for its amazing testing features, one of which is automated contract testing. It also has the ability to work with Chai and Mocha.
Populus
The Populus framework’s tests are, by default, run against an in-memory Ethereum blockchain. Populus supports writing contracts that are specifically for testing, which is powered by the python testing framework py.test. This simplifies implementation.
Ganache
This tool is solely built for testing Ethereum contracts locally. It creates a blockchain simulation that allows anyone to test using various accounts. It is important to bear in mind, however, that because the results are from a simulation they will not be perfect.
Smart contract testing
Now that you fully understand the basics of blockchain testing, we now move on to the tutorial part of this article, where we are going to develop and test a sample smart contract with Truffle.
In our example below, we create an auto shop car tracking system, and it will cover the following topics:
- Setup of the development environment
- Creation of a Truffle project
- Writing the smart contract
- Smart contract compilation
- Migrating the smart contract
- Smart contract testing
Setup of the development environment
In order to begin, the following software needs to be installed on your computer:
- Git
- npm
- js
When the installation is complete, the following command must be run in your terminal:
npm install -g truffle
Truffle will be globally installed on your computer with the command above. Typing “truffle version” in the terminal will allow you to see if Truffle is installed correctly.
Creation of a Truffle project
Use this command line to create a new project directory:
mkdir truffle-project
And move into it using this:
cd truffle-project
Then run the following code to initialize your truffle:
truffle init
The following directory structure for Truffle will be generated by the above command:
contracts/, smart contract source codes can be found here, written in Solidity. An important contract Migrations.sol can also be found within this directory.
migrations/. This migrations system manages the deployment of smart contracts. Changes in the smart contract are monitored using this.
test/ Smart contract files and test codes are stored here. Either JavaScript or Solidity can be used to write tests.
truffle-config.js Your deployment network for your smart contracts can be defined with this Truffle configuration file.
Writing a smart contract
Inside the contracts/ directory, a new file Auto.sol must be created, then the following must be added:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
contract Purchase {
address[20] public buyers;
}
pragma solidity ^0.8.9; specifies the minimum Solidity version required. The Pragma command means “additional information that only the compiler cares about”, and (^) means “the version indicated or higher”.
In writing Solidity, you must declare data types like strings and array. An address is a special data type provided by Solidity that can be used to send and receive Ether. This address is also an Ethereum address which is stored as 20-byte values.
The contract Purchase{ scope defines this public variable borrower with an address type and a length of 20. This is an array of Ethereum addresses. To avoid errors, it is imperative that you add a semicolon (;) to the end of every statement.
Now we’re going to create a function that enables users to make a borrow request. The following must be added underneath the variable declaration:
// buying a car
function buy (uint carId) public returns (uint) {
require(carId >= 0 && carId <= 19);
buyer[carId] = msg.sender;
return carId;
}
The code above indicates that the function accepts an integer (uint) parameter carId and that the output should also be an integer. To ensure that the carId is within the buyer array’s range. The carId value needs to be between zero and 19 because arrays in Solidity are indexed from zero.
As long as the carId is within the range, the address from which the call came is added to our buyer array as msg.sender. We in turn return the carId that was passed.
We next write this function:
// get all buyers
function getBuyers() public view returns (address[20] memory) {
return buyers;
}
The buyer is returned as a type address[20] memory containing the variable’s data location. view in the function declaration indicates that the contract’s state will not be changed by the function.
Smart contract compilation
After, our Solidity code must be compiled in such a way that it can be understood by the Ethereum Virtual Machine (EVM).
Type this command in your project’s root directory in your terminal:
truffle compile
This command above will compile all smart contracts in the contracts folder and also create a build directory containing a contracts folder holding artifacts.
Artifacts are bundles containing all the information that is required to interact with the smart contracts on-chain. They are stored in .json files to allow them to be shared and stored for use later without the contract being recompiled.
Migrating the smart contract
It is now time to migrate the blockchain since the contract has successfully been compiled.
Migration is the process that moves your application’s contracts from one state to the next.
Migration requires a deployment script so that the smart contract can be deployed over the blockchain. This deployment script is called the migration configuration file, and it is written in JavaScript.
Before we could deploy the smart contract with migrations, however, we first need to access their artifacts, which had been generated from the Truffle compile command. A default migration file 1_initial_migration.js which is responsible for the deployment of the Migration.sol file can be found inside the migration directory.
We will create our own migration configuration file 2_deploy_contract.js as follows:
const PurchaseContract = artifacts.require(‘Purchase’);
module.exports = function(deployer) {
deployer.deploy(PurchaseContract);
};
In order to specify the smart contract to be used for interacting with the blockchain, the artifacts.require() method is used. We specify the contract definition’s name rather than that of the .sol file because multiple contracts may be located on the source file. Therefore, we use Purchase rather than Auto.
The parameter (deployer) then exports the migrations as a function. Staging deployments are the responsibility of the object deployer. We now deploy PurchaseContract.
We will now use Ganache, another blockchain testing tool, as a localized hosting environment to deploy our smart contract and perform tests. You can either use the command line npm i -g ganache-cli or download.
The Ubuntu OS might make it difficult for you to run the Ganache application. So if you are using this OS, right-click on the application file, go to properties, then to permissions, select allow executing file as program, then re-run the application.
The Ganache GUI will be used for this tutorial. After you run the application, select quickstart and the image below will appear on your screen:
It is now time to migrate our smart contract:
truffle migrate
Once the migration is successful, you will see this:
Compiling your contracts…
===========================
> Everything is up to date, there is nothing to compile.
Starting migrations…
======================
> Network name: ‘ganache’
> Network id: 5777
> Block gas limit: 6721975 (0x6691b7)
1_initial_migration.js
======================
Replacing ‘Migrations’
———————-
> transaction hash: 0x7f4ad90e465b3e6501e8a49f3af1692ba39df66cbb6e014061b9e7e592167c02
> Blocks: 0 Seconds: 0
> contract address: 0x5A61A1989d92Fb349fAcd409Fdc8A4C640853fD9
> block number: 1
> block timestamp: 1636840180
> account: 0x3309Fa70a44a69eB7b7E87038Afa61a1C9dDB31b
> balance: 99.99502316
> gas used: 248842 (0x3cc0a)
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.00497684 ETH
> Saving migration to chain.
> Saving artifacts
————————————-
> Total cost: 0.00497684 ETH
2_deploy_contract.js
====================
Replacing ‘Purchase’
——————–
> transaction hash: 0x039224bded1eec1272e422d79ea146aa0026d13252fa7c495628829dbf7d5e42
> Blocks: 0 Seconds: 0
> contract address: 0xA89fdCd07E195be4555E07025b8613224e312F97
> block number: 3
> block timestamp: 1636840182
> account: 0x3309Fa70a44a69eB7b7E87038Afa61a1C9dDB31b
> balance: 99.98848808
> gas used: 284241 (0x45651)
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.00568482 ETH
> Saving migration to chain.
> Saving artifacts
————————————-
> Total cost: 0.00568482 ETH
Summary
=======
> Total deployments: 2
> Final cost: 0.01066166 ETH
Now return to your Ganache application:
You will realize that the current block which was four before, is now zero. In addition, the first address had started with 100 Ether but is now at 99.99 Ether due to the transaction costs of migration.
Our smart contract has now been successfully created and deployed on our local blockchain, and we are now ready to test it to ensure that it works as expected.
Smart contract testing
In Truffle, smart contracts can be tested via two methods: by using Solidity or by using JavaScript. We are going to be using the JavaScript method for this tutorial.
Create a new file purchase.test.js in the test directory and write the following:
const Purchase = artifacts.require(“Purchase”);
contract(“Purchase”, (accounts) => {
let purchase;
let expectedBuyer;
before(async () => {
purchase = await Purchase.deployed();
});
describe(“get account addresses for every purchase”, async () => {
before(“buy a car using accounts[0]”, async () => {
await purchase.buy(4, { from: accounts[0] });
expectedBuyer = accounts[0];
});
it(“can retrieve buyer’s address by car id”, async () => {
const buyer = await purchase.buyers(4);
assert.equal(buyer, expectedBuyer, “Expected to return buyer’s account.”);
});
it(“can retrieve addresses of every buyers”, async () => {
const buyers = await purchase.getBuyers();
assert.equal(buyers[4], expectedBuyer, “Buyer should be included.”);
});
});
});
First of all, we are going to use the artifacts.require() method to import our Purchase contract. Then we will declare a contract and pass in our Purchase instance as the first argument, which will be followed by a callback function as the second.
The callback function’s parameter is accounts. The network’s available accounts are provided by accounts. before is used to ensure that car ID 4 which was purchased, is assigned to the first account.
A test is then run to determine which address purchased the car with ID 4. The assert.equal method is used to compare the actual value (buyer) with the expected value (expectedBuyer). An error message is then printed to the console if the test fails.
Lastly, we check to see if all of the buyers’ addresses are returned. Then check if the address with ID 4 is among the buyer addresses returned.
Our contract is then tested by running this command:
truffle test
The following result will be received if the test passes:
Using network ‘test’.
Compiling your contracts…
===========================
> Everything is up to date, there is nothing to compile.
Contract: Purchase
get account addresses for every purchase
✓ can retrieve buyer’s address by car id (102ms)
✓ can retrieve addresses of every buyers (429ms)
2 passing (2s)
Conclusion
With the increase in blockchain adoption, it would be impossible to meet the need for high-quality products without investment in blockchain testing expertise.
Blockchain testing ensures that all system components are fully functional and that their interactions with all applications are trustworthy.