{"id":19019,"date":"2023-08-03T08:02:09","date_gmt":"2023-08-03T12:02:09","guid":{"rendered":"https:\/\/qxf2.com\/blog\/?p=19019"},"modified":"2023-08-03T08:02:09","modified_gmt":"2023-08-03T12:02:09","slug":"exploring-smart-contract-testing-in-dapps","status":"publish","type":"post","link":"https:\/\/qxf2.com\/blog\/exploring-smart-contract-testing-in-dapps\/","title":{"rendered":"Exploring Smart Contract Testing in DApps"},"content":{"rendered":"<p>At <a href=\"https:\/\/qxf2.com\/?utm_source=dappsIntro&#038;utm_medium=click&#038;utm_campaign=From%20blog\">Qxf2<\/a>, recently we began exploring blockchain technology to understand its potential applications and benefits in various industries. Our journey into testing <a href=\"https:\/\/ethereum.org\/en\/dapps\/\">DApps<\/a> started with research and self-learning. We immersed ourselves in learning about Ethereum, the leading platform for developing DApps, and its ecosystem of tools and frameworks. Understanding the nuances of <a href=\"https:\/\/soliditylang.org\/\">Solidity<\/a>, the programming language for smart contracts, was crucial for effectively testing DApps.<\/p>\n<p><strong>Note:<\/strong> You can play along with this post even if you know nothing about blockchain. We have written a simple app to help you get some hands-on experience with testing DApps.<\/p>\n<p>Smart contracts are a fundamental building block of decentralized applications (DApps) running on blockchain technology. These self-executing contracts contain the rules and logic governing DApps, ensuring transparency and immutability. As smart contracts are crucial financial transactions and sensitive data, ensuring their correctness and security is of utmost importance. As a tester, understanding how to effectively test smart contracts and DApps is crucial to ensure their functionality, security, and overall quality. In this blog post, we will explore the importance of testing smart contracts and how to set up a testing environment using popular tools like <a href=\"https:\/\/trufflesuite.com\/docs\/truffle\/\">Truffle<\/a>and <a href=\"https:\/\/trufflesuite.com\/ganache\/\">Ganache<\/a>. We will also explore a smart contract called &#8220;<a href=\"https:\/\/github.com\/indiranell\/patient-health-record-dapp\/blob\/main\/contracts\/HealthRecord.sol\">HealthRecord.sol<\/a>&#8221; and delve into its comprehensive test suite.<\/p>\n<p>Code can be found <a href=\"https:\/\/github.com\/indiranell\/patient-health-record-dapp\">here<\/a><\/p>\n<h3>Setting up the Environment<\/h3>\n<p>You might be wondering how we&#8217;ll run these tests since smart contracts are usually executed on the blockchain. Using the actual Ethereum network for testing would be expensive, and testnets, although free, can be bit slow. To overcome these challenges, we&#8217;ll utilize a local blockchain. It&#8217;s like a lightweight version of the real Ethereum network that runs on your computer and doesn&#8217;t require an internet connection.<\/p>\n<p>To begin testing, we used <a href=\"https:\/\/trufflesuite.com\/docs\/truffle\/\">Truffle<\/a> and <a href=\"https:\/\/trufflesuite.com\/ganache\/\">Ganache<\/a>, popular tools for smart contract development and testing. By setting up Ganache and Truffle, you can create a local testing environment for your smart contract development and testing. This makes testing simpler and faster. <\/p>\n<p>Truffle provides a development environment, testing framework for DApps.<br \/>\nGanache serves as a local blockchain network for testing purposes. The installation steps are listed in <a href=\"https:\/\/github.com\/indiranell\/patient-health-record-dapp\/blob\/main\/README.md\">readme.md<\/a><\/p>\n<p>We are testing our smart contract on the local network and once after completing all our testing, we have deployed our smart contract to Testnet <a href=\"https:\/\/www.alchemy.com\/overviews\/sepolia-testnet\">Sepolia<\/a>. Sepolia ETH can be obtained from a <a href=\"https:\/\/sepoliafaucet.com\/\">Sepolia testnet faucet<\/a>, that allows anyone to send a small amount of fake Sepolia ETH to their wallet. <\/p>\n<h3>Our Patient Record DApp<\/h3>\n<p>We built a small DApp around our smart contract to explore the potential of decentralized applications. Using <a href=\"https:\/\/trufflesuite.com\/boxes\/react\/\">Truffle React Box<\/a> we quickly set up the front-end. This DApp, for every patient addition creates a transaction in the network. While testing this DApp, we realized the criticality of smart contract testing and thorough testing was essential to ensure the reliability, security, and integrity of DApps. With this understanding, we shifted our focus from the user interface to the testing of smart contracts. <\/p>\n<p>You can find our DApp code <a href=\"https:\/\/github.com\/indiranell\/patient-health-record-dapp\">here<\/a>. You can refer our Readme.md file on how to start the application. In the next sections, we will be focusing on testing the smart contracts.<\/p>\n<figure id=\"attachment_19262\" aria-describedby=\"caption-attachment-19262\" style=\"width: 900px\" class=\"wp-caption alignleft\"><a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2023\/07\/dapp-1.png\" data-rel=\"lightbox-image-0\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2023\/07\/dapp-1-1024x351.png\" alt=\"Patient Health Record DApp\" width=\"900\" height=\"308\" class=\"size-large wp-image-19262\" srcset=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2023\/07\/dapp-1-1024x351.png 1024w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2023\/07\/dapp-1-300x103.png 300w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2023\/07\/dapp-1-768x264.png 768w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2023\/07\/dapp-1-1536x527.png 1536w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2023\/07\/dapp-1.png 1579w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/a><figcaption id=\"caption-attachment-19262\" class=\"wp-caption-text\">Patient Health Record DApp<\/figcaption><\/figure>\n<h3>About the HealthRecord Smart Contract<\/h3>\n<p>The <a href=\"https:\/\/github.com\/indiranell\/patient-health-record-dapp\/blob\/main\/contracts\/HealthRecord.sol\">HealthRecord.sol<\/a> smart contract is designed to manage health records on a blockchain network. The HealthRecord smart contract provides basic functionalities for managing patient records, including adding, updating, and deleting records, while emitting events to track these actions on the blockchain. In the &#8216;contracts&#8217; folder of the project directory, you can find &#8216;HealthRecord.sol&#8217; contract.<\/p>\n<p>The contract includes three core functions:<\/p>\n<p><strong>addPatient<\/strong>: This function adds a new patient record to the mapping, but it checks if a patient with the same ID already exists. It also ensures that the name provided is non-empty. We use the <em>require<\/em> statement to enforce these two conditions.<\/p>\n<p>So if an empty name is provided, the transaction will be reverted, and an error message &#8220;<em>Name must not be empty<\/em>&#8221; will be displayed. Similarly, If a patient with the same ID already exists, the transaction will be reverted, and an error message &#8220;<em>Patient with this ID already exists<\/em>&#8221; will be displayed. If both the conditions are met, <em>PatientAdded<\/em> event is emitted using the emit statement. <\/p>\n<pre lang=\"Solidity\">\r\nevent PatientAdded(uint256 indexed id, string name, uint256 age);\r\nfunction addPatient(uint256 id, string memory name, uint256 age) public returns (bytes32) {\r\n        require(patients[id].id != id, \"Patient with the given ID already exists\");\r\n        require(bytes(name).length > 0, \"Name field is required\");     \r\n        patients[id] = Patient(id, name, age);       \r\n        emit PatientAdded(id, name, age);        \r\n    }<\/pre>\n<p><strong>updatePatient<\/strong>: This function updates an existing patient record based on the oldId. It validates the newName using `require` statement.<br \/>\nRetrives patient record associated with `oldId` from `patients` mapping and stores it. Updates the patient details by assigning the `newID, newName and newAge.<br \/>\nFinally, emits the <em>PatientUpdated<\/em> event, passing the newId, newName, and newAge as event parameters. This event notifies external applications about the successful update to the patient&#8217;s details.<\/p>\n<pre lang=\"Solidity\">\r\nevent PatientUpdated(uint256 indexed id, string name, uint256 age);\r\nfunction updatePatient(uint256 oldId, uint256 newId, string memory newName, uint256 newAge) public returns (bytes32) {\r\n        require(bytes(newName).length > 0, \"Name field is required\");       \r\n        Patient storage patient = patients[oldId];        \r\n        patient.id = newId;\r\n        patient.name = newName;\r\n        patient.age = newAge;        \r\n        emit PatientUpdated(newId, newName, newAge);        \r\n    }<\/pre>\n<p><strong>deletePatient<\/strong>: This function deletes the patient record associated with the given id from the patients mapping using the <em>delete<\/em> keyword. It emits <em>PatientDeleted<\/em> event passing the `id` as event parameter. This event notifies external applications about the successful deletion of the patient record.<\/p>\n<pre lang=\"Solidity\">\r\n event PatientDeleted(uint256 indexed id);\r\n function deletePatient(uint256 id) public {        \r\n        delete patients[id];        \r\n        emit PatientDeleted(id);\r\n    }<\/pre>\n<p>In the following section we will explore different test scenarios which we wrote to test this Smart contract.<\/p>\n<h3>Test Suite Overview<\/h3>\n<p>Testing a smart contract is essential to ensure its functionality, reliability, and security. In the case of the above HealthRecord.sol smart contract, the below provided tests cover different scenarios and functionalities to validate its behavior. Let&#8217;s discuss the testing approach and the purpose of each test. Code can be found <a href=\"https:\/\/github.com\/indiranell\/patient-health-record-dapp\/blob\/main\/test\/test_smart_contract.js\">here<\/a><\/p>\n<p><a href=\"https:\/\/trufflesuite.com\/docs\/truffle\/how-to\/debug-test\/test-your-contracts\/\">Truffle test framework<\/a> gives us two options for writing tests for Smart contracts. <a href=\"https:\/\/trufflesuite.com\/docs\/truffle\/how-to\/debug-test\/write-tests-in-solidity\/\">Solidity tests<\/a> and <a href=\"https:\/\/trufflesuite.com\/docs\/truffle\/how-to\/debug-test\/write-tests-in-javascript\/\">JavaScript<\/a> tests. We used JavaScript for writing tests.<\/p>\n<p>Truffle uses the <a href=\"https:\/\/mochajs.org\/\">Mocha<\/a> testing framework and <a href=\"https:\/\/www.chaijs.com\/\">Chai<\/a> for assertions for writing JavaScript tests. To begin with, the code sets up the necessary environment and initializes variables for testing the functionalities of the HealthRecord contract. <\/p>\n<pre lang=\"javascript\">\r\nconst HealthRecord = artifacts.require('HealthRecord');\r\ncontract('HealthRecord', (accounts) => {\r\n    let healthRecordInstance;\r\n    const addedPatients = [];\r\n\r\n    beforeEach(async () => {\r\n        healthRecordInstance = await HealthRecord.deployed();       \r\n    });\r\n  <\/pre>\n<p>The above code in the test does the following:<\/p>\n<li>The HealthRecord contract artifact is imported, allowing interaction with the deployed contract. <\/li>\n<li>The healthRecordInstance variable is declared to hold an instance of the HealthRecord contract. <\/li>\n<li>A &#8220;before each&#8221; hook is used to assign the deployed instance of the HealthRecord contract to the healthRecordInstance variable, facilitating easy access to the contract throughout the tests.<\/li>\n<h4>Grouping TestCases<\/h4>\n<p>When a smart contract has a significant number of unit tests, it becomes challenging to read and maintain. Truffle&#8217;s integration with Mocha allows for a more organized and readable testing approach using nested describe() functions. By leveraging nested describe() functions, we grouped related test cases together, creating a more structured and organized test suite as discussed below:<\/p>\n<p>Basic Functionality:<br \/>\nThese tests cover the basic functionality of adding and retrieving patient records in the HealthRecord contract. They validate that patient records are added correctly and can be retrieved accurately, providing a strong foundation for the core functionality of the contract.<\/p>\n<p>Error Handling:<br \/>\nValidates how the contract handles exceptional cases, such as adding a patient record with an empty name field.<br \/>\nVerifies that appropriate errors are thrown when attempting to add duplicate patient IDs.<\/p>\n<p>Event Emission:<br \/>\nVerifies the emission of the PatientAdded event when a patient record is added successfully. Ensures the contract emits the expected event and event parameters are accurate.<\/p>\n<p>Edge Cases:<br \/>\nTests scenarios where non-existing patient records are retrieved, ensuring default values are returned.<br \/>\nValidates the ability of the contract to handle and retrieve multiple patient records accurately.<\/p>\n<p>Data Integrity:<br \/>\nChecks if the contract maintains data integrity during record addition, modification, and retrieval.<br \/>\nVerifies that the stored values accurately reflect the intended changes.<\/p>\n<pre lang=\"javascript\">\r\ncontract(\"HealthRecord TestCases\", async accounts => {\r\n  describe(\"Basic Functionality\", () => {\r\n    it(\"should add a patient record\", async() => {\r\n      ...\r\n    });\r\n    it(\"should retrieve a patient record for a non-existing ID\", async() => {\r\n      ...\r\n    });\r\n    it(\"should update an existing patient record\", async() => {\r\n      ...\r\n    });\r\n    it(\"should handle retrieving a patient record from a different account\", async() => {\r\n      ...\r\n    });\r\n  });\r\n\r\n describe(\"Error Handling\", () => {\r\n    it(\"should handle empty fields during record addition\", async() => {\r\n      ...\r\n    });\r\n    it(\"should not add duplicate patient ID\", async() => {\r\n      ...\r\n    });\r\n  });\r\n\r\n describe(\"Event Emission\", () => {\r\n        it(\"should emit PatientAdded event\", async () => {\r\n      ...\r\n    });\r\n  });\r\n\r\n describe(\"Data Consistency\", () => {\r\n    it(\"should update patient age correctly\", async() => {\r\n      ...\r\n    });\r\n\r\n<\/pre>\n<p>The test can be found <a href=\"https:\/\/github.com\/indiranell\/patient-health-record-dapp\/blob\/main\/test\/test_smart_contract.js\">here<\/a>. You can execute the test like this. <\/p>\n<p>`truffle test`<\/p>\n<p>And the output looks like this:<\/p>\n<figure id=\"attachment_19260\" aria-describedby=\"caption-attachment-19260\" style=\"width: 900px\" class=\"wp-caption alignleft\"><a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2023\/07\/result-2.png\" data-rel=\"lightbox-image-1\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2023\/07\/result-2-1024x704.png\" alt=\"Truffle Test output\" width=\"900\" height=\"619\" class=\"size-large wp-image-19260\" srcset=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2023\/07\/result-2-1024x704.png 1024w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2023\/07\/result-2-300x206.png 300w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2023\/07\/result-2-768x528.png 768w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2023\/07\/result-2.png 1053w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/a><figcaption id=\"caption-attachment-19260\" class=\"wp-caption-text\">Truffle Test output<\/figcaption><\/figure>\n<h4>Keywords: require, events<\/h4>\n<p>To confirm more thoroughly whether a smart contract behaves as expected or not, smart contract tests should verify fired <a href=\"https:\/\/solidity-by-example.org\/events\/\">events<\/a>. The error messages from <a href=\"https:\/\/www.alchemy.com\/overviews\/learn-solidity#require-error-handling\">require<\/a> statements are captured in the test cases using <em>try\/catch<\/em>. We use the <a href=\"https:\/\/consensys.github.io\/smart-contract-best-practices\/development-recommendations\/solidity-specific\/assert-require-revert\/\">assert<\/a> statement to verify that the error message matches the expected error. we can assert and validate the correctness of the error messages thrown by the smart contract when specific conditions are not met. This approach allows us to effectively test the error handling behavior of the contract and ensure that it responds appropriately to exceptional cases. <\/p>\n<hr\/>\n<p>We covered various test scenarios, including testing basic functionalities, handling errors, verifying event emissions, and checking data consistency. Each test case played a critical role in validating the correctness of the HealthRecord smart contract, providing users with confidence in its performance and reliability. You can explore more advanced techniques to help identify bugs and vulnerabilities in contract logic. Smart Testing !!!<\/p>\n<hr\/>\n<h4>References<\/h4>\n<p>1. <a href=\"https:\/\/docs.infura.io\/tutorials\/ethereum\/create-a-dapp-using-truffle-and-react\">Create a DApp using Truffle and React<\/a><br \/>\n2. <a href=\"https:\/\/betterprogramming.pub\/a-few-tips-for-unit-testing-ethereum-smart-contract-in-solidity-d804062068fb\">Few tips for unit testing smart contracts<\/a><br \/>\n3. <a href=\"https:\/\/rhian-is.medium.com\/how-to-test-dapps-decentralized-applications-4662cf61db90\">How to test dapps<\/a><br \/>\n4. <a href=\"https:\/\/www.dappuniversity.com\/articles\/ethereum-dapp-react-tutorial\">Etherium DApp Tutorial<\/a><br \/>\n5. <a href=\"https:\/\/web3js.readthedocs.io\/en\/v1.10.0\/\">Web3.js documentation<\/a><\/p>\n<hr>\n<h4>Outsource your testing to Qxf2!<\/h4>\n<p><a href=\"https:\/\/qxf2.com\/contact?utm_source=dappsIntro&#038;utm_medium=click&#038;utm_campaign=From%20blog\">Choose Qxf2<\/a> to elevate your software testing capabilities with our team of technical testers. We excel in testing early-stage products powered by cutting-edge technology stacks. Our expertise in going beyond conventional test automation empowers us to tackle intricate testing challenges, ensuring your product meets the highest quality standards. With Qxf2, you&#8217;ll have a dedicated partner who can help you iterate quickly, identify critical bugs, and optimize your development processes for seamless delivery. <\/p>\n<hr>\n","protected":false},"excerpt":{"rendered":"<p>At Qxf2, recently we began exploring blockchain technology to understand its potential applications and benefits in various industries. Our journey into testing DApps started with research and self-learning. We immersed ourselves in learning about Ethereum, the leading platform for developing DApps, and its ecosystem of tools and frameworks. Understanding the nuances of Solidity, the programming language for smart contracts, was [&hellip;]<\/p>\n","protected":false},"author":16,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[371,373,372,378,375],"tags":[],"class_list":["post-19019","post","type-post","status-publish","format-standard","hentry","category-blockchain","category-dapp","category-smart-contracts","category-solidity","category-web3-js"],"_links":{"self":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/19019","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/users\/16"}],"replies":[{"embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/comments?post=19019"}],"version-history":[{"count":69,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/19019\/revisions"}],"predecessor-version":[{"id":19332,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/19019\/revisions\/19332"}],"wp:attachment":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/media?parent=19019"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/categories?post=19019"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/tags?post=19019"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}