Smart Contract Unit Testing on the Celo Blockchain Using Remix

Smart Contract Unit Testing on the Celo Blockchain Using Remix https://celo.academy/uploads/default/optimized/2X/d/d6301417fb96c1759f9211026ba34b4f2574a34c_2_1024x576.png
none 0.0 0

Introduction

The Celo blockchain is an open-source, mobile-first blockchain platform that enables fast, secure, and efficient decentralized applications and crypto assets. Like Ethereum, it also allows developers to write and deploy smart contracts using the Solidity programming language.

In this article, we will guide you through the process of testing smart contracts on Celo using the Remix IDE, an open-source web application for developing, testing, and deploying smart contracts in Solidity.

Prerequisites

These tutorials assume that you have some basic knowledge of solidity

This is a list of what we’ll cover :spiral_notepad:

  • :white_check_mark: Step 1: Creating a new project
  • :white_check_mark: Step 2: Testing the smart contract
  • :white_check_mark: Step 3: Compiling and deploying the smart contract

Unit Testing

Unit testing is a testing method performed to verify the functionality and reliability of smart contracts. Smart contracts are computer programs that run autonomously on the blockchain. Unit testing involves writing test code that calls individual functions or methods in the contract code with appropriate inputs and verifies the expected outputs.

This type of testing is often used by developers to ensure that their smart contracts are working as intended before they are deployed to the blockchain. It can also be used by auditors to verify the security and reliability of smart contracts before they are used by users. Unit testing is a valuable tool for ensuring the quality of smart contracts. It can help to prevent errors and vulnerabilities that could lead to loss of funds or other problems.

Step 1: Creating a new project

  1. Open the Remix IDE in your browser

  2. Click on the File Explorer icon on the left side of the screen, then create a new workspace by clicking on the + icon

  3. Chose a template for your project. For this tutorial, we will use the Basic template and name our project Unit Testing, then click on Ok

  4. You will see a structure project like this

  5. Now, we will create a new file named MyToken.sol by right-clicking on the contracts folder and selecting New File

    In this tutorial, we will create simple smart contracts named MyToken.sol. These contracts will be used in unit testing. The code for these contracts can be found below:

    MyToken.sol contract will be used openzeppelin library to create a simple ERC20 token

    // SPDX-License-Identifier: MIT
    
    pragma solidity 0.8.15;
    
    import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
    import "@openzeppelin/contracts/access/Ownable.sol";
    
    contract MyToken is ERC20, Ownable {
    
       uint256 public rate;
    
      event Buy(address indexed buyer, uint256 amount);
      event Withdraw(address indexed owner, uint256 amount);
        
      constructor() ERC20("Test Token", "TT") {
         rate = 100;
      }
    
      function buy() external payable {
         require(msg.value > 0);
         uint256 amount = msg.value * rate;
         _mint(msg.sender, amount);
         emit Buy(msg.sender, amount);
      }
    
    
      // Owner withdraw fund from token sale
      function withdraw() external onlyOwner {
         uint256 amount = address(this).balance;
         (bool status, ) = msg.sender.call{value:amount}("");
         require(status);
         emit Withdraw(msg.sender, amount);
      }
    }
    

Step 2: Testing the Smart Contract

  1. First, we need to activate the Solidity Unit Testing plugin by clicking on the Plugins Manager icon on the left side of the screen

  2. Next, create a new file named myToken.test.js by right-clicking on the test folder and selecting New File

  3. Now, we will write a unit test for the MyToken.sol contract.

     const { expect } = require("chai");
     const { ethers } = require("hardhat");
    

    First, we need to import the modules that we will use in our unit tests. We will use chai for assertions, ethers from hardhat to connect to the blockchain and send transactions to contracts.

     ```javascript
     describe("MyToken", function(){
         // Code for test
     })
     ```
    

    Next, we will create a test suite for the MyToken contract. A test suite is a collection of test cases that are related to each other. In this case, we will create a test suite for the MyToken contract.

    it("Owner is developer address", async function () {
       const account = await ethers.getSigners();
       const MyToken = await ethers.getContractFactory("MyToken");
       const token = await MyToken.deploy();
       await token.deployed();
       expect((await token.owner())).to.be.equal(account[0].address);
    });
    

    Next, we will create a test case for the owner function of the MyToken contract. This function returns the address of the owner of the contract. We will use the expect function from chai to check if the address returned by the owner function is equal to the address of the developer.

    it("Owner transfer ownership", async function () {
       const account = await ethers.getSigners();
       const MyToken = await ethers.getContractFactory("MyToken");
       const token = await MyToken.deploy();
       await token.deployed();
    
       await token.transferOwnership(account[1].address);
       expect(
          (await token.owner())
       ).to.be.equal(account[1].address);
    });
    

    Next, we will create a test case for the transferOwnership function of the MyToken contract. This function transfers the ownership of the contract to another address. We will use the expect function from chai to check if the address returned by the owner function is equal to the address of the developer.

    it("Buy token", async function(){
       const account = await ethers.getSigners();
       const MyToken = await ethers.getContractFactory("MyToken");
       const token = await MyToken.deploy();
       await token.deployed();
    
       await token.connect(account[1]).buy({value:ethers.utils.parseEther("0.5")});
       expect((await token.balanceOf(account[1].address)).toString()).to.be.equal("50000000000000000000");
    });
    

    Next, we will create a test case for the buy function of the MyToken contract. This function allows users to buy tokens from the contract. We will use the expect function from chai to check if the balance of the user is equal to the amount of tokens they bought.

    it("Owner withdraw fee", async function(){
       const account = await ethers.getSigners();
       const MyToken = await ethers.getContractFactory("MyToken");
       const token = await MyToken.deploy();
       await token.deployed();
    
       let amount = ethers.utils.parseEther("0.5");
    
       // Buy token
       await token.connect(account[1]).buy({value:amount});
    
       // Dev claim fee
       await token.withdraw();
    
       // Get contract balance
       let contractBalance = await ethers.provider.getBalance(token.address);
       expect(contractBalance.toString()).to.be.equal("0");
    });
    

    Next, we will create a test case for the withdraw function of the MyToken contract. This function allows the owner of the contract to withdraw the fee from the contract. We will use the expect function from chai to check if the balance of the contract is equal to 0 after the owner withdraws the fee.

    Complete code for myToken.test.js file

    const { expect } = require("chai");
    const { ethers } = require("hardhat");
    
    describe("MyToken", function () {
        it("Owner is developer address", async function () {
             const account = await ethers.getSigners();
             const MyToken = await ethers.getContractFactory("MyToken");
             const token = await MyToken.deploy();
             await token.deployed();
             expect((await token.owner())).to.be.equal(account[0].address);
         });
    
         it("Owner transfer ownership", async function () {
             const account = await ethers.getSigners();
             const MyToken = await ethers.getContractFactory("MyToken");
             const token = await MyToken.deploy();
             await token.deployed();
    
             await token.transferOwnership(account[1].address);
             expect(
                 (await token.owner())
             ).to.be.equal(account[1].address)
         });
    
         it("Buy token", async function(){
              const account = await ethers.getSigners();
              const MyToken = await ethers.getContractFactory("MyToken");
              const token = await MyToken.deploy();
              await token.deployed();
    
              await token.connect(account[1]).buy({value:ethers.utils.parseEther("0.5")});
              expect((await token.balanceOf(account[1].address)).toString()).to.be.equal("50000000000000000000");
            });
    
          it("Owner withdraw fee", async function(){
            const account = await ethers.getSigners();
             const MyToken = await ethers.getContractFactory("MyToken");
             const token = await MyToken.deploy();
             await token.deployed();
    
             let amount = ethers.utils.parseEther("0.5")
    
             // Buy token
             await token.connect(account[1]).buy({value:amount});
    
             // Dev claim fee
              await token.withdraw();
    
             // Get contract balance
             let contractBalance = await ethers.provider.getBalance(token.address)
             expect(contractBalance.toString()).to.be.equal("0");
       })
     });
    
  4. Now, we will run the unit tests, right-click on the mytoken.test.js file and select Run

Step 3: Compiling and deploying the smart contract

  1. Now, we will compile the smart contract. Open MyToken.sol file, and look compiler icon on the left side of the editor.

    Choose the compiler version 0.8.15 and in the contract dropdown, choose MyToken.sol. Then click on the compile button.

  2. To deploy the smart contract, click on the Ethereum icon in the left sidebar of the editor.

    In the environment dropdown, select Injected Web3. Then, in the contract dropdown, select MyToken.sol. Finally, click on the Deploy button.

    You should see the contract deployed in the Deployed Contracts section.

    Now, we can interact with the smart contract using the Remix IDE UI.

Conclusion

Testing smart contracts is a vital step in the development process. It ensures that your contracts are secure, efficient, and function as expected. Remix IDE provides an excellent environment for writing, deploying, and testing Solidity smart contracts for Celo and other Ethereum-like blockchains.

However, while Remix provides an excellent environment for development and initial testing, it is important to use thorough and automated testing strategies as your contract complexity grows. This will help to ensure maximum security and reliability.

It is also important to remember that blockchain transactions are irreversible, and any bug in a live smart contract could result in significant financial losses. Therefore, it is essential to test your smart contracts thoroughly before deploying them to the blockchain.

Next steps

You can try creating your own smart contract using the Remix IDE. To learn more about the Remix IDE, you can read the official Remix IDE documentation here You can also try some other smart contract frameworks, such as Truffle and Hardhat

About the Author

Joel Obafemi

A marketer, copywriter, and collab manager for web3 brands. You can connect with me on LinkedIn.

References

Source Code

7 Likes

Looks interesting. I will love to see the outcome

2 Likes

This appears to be a tutorial rather than a pathway. Removing the pathway tag.

3 Likes

Congratulations on being among the highest voted proposals for this week! I’m moving this to todo so that you can get started on this project. :mortar_board: :seedling:

3 Likes

I will do a review

Hi @Joel

Based on the title of your post, I see that you plan to test smart contracts using the Remix IDE. I suggest that you try some of the plugins available in the Remix IDE, such as Solidity static analysis, Solidity unit testing, and Sourcify. You can also test using web3.js or ethers.js in Remix IDE. Because the current content only shows how to deploy and interact with smart contracts using the Remix IDE, I think it would be helpful to add a section on how to test smart contracts using the Remix IDE.

5 Likes

Hi @yafiabiyyu ,

Thanks for your message.

I’ll do as suggested.

4 Likes

Thanks, I appreciate that

4 Likes

any update @Joel ?

3 Likes

How about now?

2 Likes

Check Personal message from me, for new sugestion

4 Likes

Thank you @Joel for this tutorial,

This is short and simple. As a beginner, a quick run through the code would help me learn more.

2 Likes

Please make sure to not to move the articles in publish section , if it is not ready

2 Likes

is something missing?

3 Likes

Yeah actually there are a couple of things I can point to
I’ll leave a comment for both reviewer @yafiabiyyu and author @Joel to take note of :clinking_glasses:

2 Likes

I appreciate your tutorial, @Joel.

It’s concise and straightforward, which is perfect for someone like me who’s just starting out. Going through the code quickly would enhance my learning experience.

2 Likes