Testing and Deploying the Voting DApp Smart Contract

chainyblockchainyblock
5 min read

A person typing on a keyboard, with a smartwatch on their wrist, in front of a computer monitor displaying code.

Welcome back to our series on building a decentralized voting application (DApp) using the Ethereum network! In Article 2 , we developed the Solidity smart contract that powers our voting system. Now it’s time to test the contract thoroughly and deploy it to the Sepolia testnet using Hardhat and Alchemy.

In this article, we’ll walk through:

  1. Testing the Smart Contract : Using Hardhat to write and run unit tests for the smart contract.

  2. Deploying to the Sepolia Testnet : Configuring Hardhat to deploy the contract to the Sepolia testnet via Alchemy.

  3. Verifying Deployment : Ensuring the contract is deployed successfully and ready for use.

Let’s dive in!

Testing the Smart Contract with Hardhat

Before deploying our smart contract to the blockchain, it’s crucial to test it thoroughly to ensure it behaves as expected. We’ll use Hardhat, a powerful development environment for Ethereum, to write and execute unit tests.

Why Test?

Testing ensures that:

  • The contract logic works as intended.

  • Edge cases are handled correctly.

  • Users can’t exploit vulnerabilities or bypass rules.

The Testing Framework

Here’s how we’ll structure our tests:

  • Deployment Tests : Verify that the contract deploys correctly and initializes key variables like owner, electionCount, and candidateCount.

  • Election Tests : Ensure elections can be created, retrieved, and validated.

  • Candidate Tests : Confirm candidates can be registered and linked to elections.

  • Voter Tests : Validate voter registration and voting restrictions.

  • Voting Process Tests : Test vote casting, double voting prevention, and election results.

  • Election End Tests : Verify that elections can be ended and winners determined.

Example Test Cases

  1. Creating Elections

     it("Should create a new election", async function () {
         const currentTime = await getCurrentTime();
         const startTime = currentTime + daysToSeconds(1); // Start 1 day from now
         const endTime = currentTime + daysToSeconds(8); // End 8 days from now
         await votingSystem.createElection(
             "Presidential Election 2025",
             "National presidential election",
             startTime,
             endTime
         );
         expect(await votingSystem.electionCount()).to.equal(1);
         const election = await votingSystem.getElectionDetails(1);
         expect(election.name).to.equal("Presidential Election 2025");
     });
    

    This test ensures that an election can be created with valid parameters and retrieves its details.

  2. Registering Candidates

     it("Should register a candidate for an election", async function () {
         await votingSystem.registerCandidate(
             1,
             "John Doe",
             "Independent Party",
             "Former governor"
         );
         expect(await votingSystem.candidateCount()).to.equal(1);
         const candidate = await votingSystem.getCandidateDetails(1);
         expect(candidate.name).to.equal("John Doe");
     });
    

    This test validates that candidates can be registered for specific elections.

  3. Casting Votes

     it("Should allow registered voters to cast votes", async function () {
         await votingSystem.connect(addr1).castVote(1, 1);
         const candidate = await votingSystem.getCandidateDetails(1);
         expect(candidate.voteCount).to.equal(1);
         expect(await votingSystem.hasVoted(addr1.address, 1)).to.be.true;
     });
    

    This test ensures that registered voters can cast their votes and that votes are recorded correctly.

  4. Determining Winners

     it("Should determine the correct winner", async function () {
         const winnerId = await votingSystem.getWinner(1);
         expect(winnerId).to.equal(1); // Candidate 1 has 2 votes vs 1 vote for Candidate 2
         const winnerDetails = await votingSystem.getCandidateDetails(winnerId);
         expect(winnerDetails.name).to.equal("Candidate 1");
     });
    

    This test verifies that the getWinner function correctly identifies the candidate with the most votes.

    Running the Tests

    To run the tests, use the following command:

     npx hardhat test
    

    If all tests pass, you’ll see output like this:

       VotingSystem
         Deployment
           ✓ Should set the right owner
           ✓ Should start with no elections
           ✓ Should start with no candidates
         Elections
           ✓ Should create a new election
           ✓ Should not allow non-owners to create elections
           ✓ Should return active elections
         Candidates
           ✓ Should register a candidate for an election
           ✓ Should not allow registering candidates for non-existent elections
         Voting Process
           ✓ Should allow registered voters to cast votes
           ✓ Should not allow unregistered voters to cast votes
         Election Results
           ✓ Should determine the correct winner
           ✓ Should allow ending an election
    
       20 passing (2s)
    

Deploying to the Sepolia Testnet

Once the tests pass, it’s time to deploy the contract to the Sepolia testnet. We’ll use Alchemy as our Ethereum node provider and Hardhat for deployment.

Step 1: Set Up Alchemy

  1. Go to Alchemy and create a new app for the Sepolia testnet.

  2. Copy the API key from your Alchemy dashboard.

Step 2: Configure Hardhat

Update the hardhat.config.js file to include the Sepolia network and your Alchemy API key:

require("@nomicfoundation/hardhat-toolbox");

// Ensure your configuration variables are set before executing the script
const { vars } = require("hardhat/config");

// Go to https://alchemy.com, sign up, create a new App in
// its dashboard, and add its key to the configuration variables
const ALCHEMY_API_KEY = vars.get("TEST_API_KEY");

// Add your Sepolia account private key to the configuration variables
// To export your private key from Coinbase Wallet, go to
// Settings > Developer Settings > Show private key
// To export your private key from Metamask, open Metamask and
// go to Account Details > Export Private Key
// Beware: NEVER put real Ether into testing accounts
const SEPOLIA_PRIVATE_KEY = vars.get("SEPOLIA_PRIVATE_KEY");

module.exports = {
  solidity: "0.8.28",
  networks: {
    sepolia: {
      url: `https://eth-sepolia.g.alchemy.com/v2/${ALCHEMY_API_KEY}`,
      accounts: [SEPOLIA_PRIVATE_KEY]
    }
  }
};

Replace YOUR_ALCHEMY_API_KEY with your actual Alchemy API key and YOUR_PRIVATE_KEY with your wallet’s private key.

Step 3: Write the Deployment Script

Create a deployment script (./ignition/modules/Voting.js) to deploy the contract:

// This setup uses Hardhat Ignition to manage smart contract deployments.
// Learn more about it at https://hardhat.org/ignition

const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules");

const VotingModule = buildModule("VotingModule", (m) => {
  const voting = m.contract("VotingSystem");

  return { voting };
});

module.exports = VotingModule;

Step 4: Deploy the Contract

Run the deployment script:

npx hardhat ignition deploy ./ignition/modules/Voting.js --network sepolia

If successful, you’ll see output like this:

Hardhat Ignition 🚀

Deploying [ VotingModule ]

Batch #1
  Executed VotingModule#VotingSystem

[ VotingModule ] successfully deployed 🚀

Deployed Addresses

VotingModule#VotingSystem - 0xYourContractAddress

Interacting with the Deployed Contract

Once deployed, you can interact with the contract using tools like:

  • Ethers.js : To connect the frontend (covered in Article 4).

  • Etherscan : To view transactions and contract details.

For example, you can call the createElection function to create a new election directly on the blockchain.

Wrapping Up

Congratulations—you’ve successfully tested and deployed your voting DApp smart contract to the Sepolia testnet! This is a major milestone in building your decentralized voting system.

Your Task : Try deploying the contract yourself and share your experience in the comments. Did you encounter any challenges? How did you resolve them?

Stay tuned for Article 4 , where we’ll develop the frontend using React and connect it to the smart contract using Ethers.js. See you there! 🚀

0
Subscribe to my newsletter

Read articles from chainyblock directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

chainyblock
chainyblock

👋 Hi, We are ChainyBlock, a passionate advocate for blockchain technology and its transformative potential. With a background in software engineering and cybersecurity, We've spent a lot of time exploring how decentralized systems can reshape industries, foster trust, and create a more inclusive future. 🎯 What Drives Me? I believe that understanding complex technologies like blockchain shouldn’t be reserved for experts—it should be accessible to everyone. That’s why I’m here: to break down the fundamentals of Web3, cryptocurrencies, smart contracts, and decentralized applications into simple, actionable insights. Whether you’re a beginner or a seasoned learner, my goal is to help you navigate this rapidly evolving space with confidence. 💭 Dreams for the Future: I dream of a world where blockchain technology enables secure, transparent, and efficient systems for everyone—regardless of location or background. Through education and collaboration, I hope to inspire others to embrace the possibilities of Web3 and contribute to this global movement. 🌟 Let’s Connect: Feel free to reach out if you’d like to discuss blockchain innovations, collaborate on projects, or share ideas. Together, we can build a smarter, decentralized future. 🌐💡