🧪 HARDHAT & FOUNDRY: Testing como un Pro

Escribe tests que detectan bugs antes de desplegar ” porque en blockchain no hay "deshacer"

Semanas 1-2: Testing de Smart Contracts
Hardhat (JS/TS) Foundry (Solidity) Fuzz Testing Coverage
🧪 Piénsalo así: Desplegar un smart contract sin tests es como construir un puente y cortar la cinta de inauguración sin haberlo probado con carga real. En blockchain, una vez desplegado el contrato, no puedes parchearlo (a menos que uses proxies). Un bug como el DAO Hack de 2016 drenó $60M. Hardhat usa JavaScript/TypeScript ” ideal si ya sabes JS. Foundry usa Solidity puro para los tests ” más rápido y con fuzzing integrado. Los mejores proyectos DeFi usan ambos.
📚 Refs: Hardhat Docs ” hardhat.org · Foundry Book ” book.getfoundry.sh · "The DAO Hack" ” Ethereum Foundation Blog (2016)
Hardhat (JS)
Foundry (Solidity)
Fuzz Testing

Test Suite en Hardhat ” Token ERC-20

// test/Token.test.js ” Hardhat + Chai
const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("MyToken", function() {
 let token, owner, alice, bob;

 beforeEach(async function() {
  [owner, alice, bob] = await ethers.getSigners();
  const Token = await ethers.getContractFactory("MyToken");
  token = await Token.deploy(ethers.parseEther("1000000"));
  await token.waitForDeployment();
 });

 describe("Deployment", function() {
  it("assigns total supply to owner", async function() {
   const ownerBal = await token.balanceOf(owner.address);
   expect(ownerBal).to.equal(ethers.parseEther("1000000"));
  });
 });

 describe("Transfers", function() {
  it("transfers tokens between accounts", async function() {
   await token.transfer(alice.address, 100n);
   expect(await token.balanceOf(alice.address)).to.equal(100n);
  });

  it("reverts with insufficient balance", async function() {
   await expect(
    token.connect(alice).transfer(bob.address, 1n)
   ).to.be.revertedWith("ERC20: insufficient balance");
  });

  it("emits Transfer event", async function() {
   await expect(token.transfer(alice.address, 50n))
    .to.emit(token, "Transfer")
    .withArgs(owner.address, alice.address, 50n);
  });
 });
});
$ npx hardhat test test/Token.test.js

Test Suite en Foundry ” Solidity puro

// test/Token.t.sol ” Foundry + forge-std
pragma solidity ^0.8.20;
import {Test, console} from "forge-std/Test.sol";
import {MyToken} from "../src/MyToken.sol";

contract TokenTest is Test {
  MyToken token;
  address owner = makeAddr("owner");
  address alice = makeAddr("alice");

  function setUp() public {
    vm.startPrank(owner);
    token = new MyToken(1_000_000e18);
    vm.stopPrank();
  }

  function test_InitialSupply() public view {
    assertEq(token.balanceOf(owner), 1_000_000e18);
  }

  function test_Transfer() public {
    vm.prank(owner);
    token.transfer(alice, 100e18);
    assertEq(token.balanceOf(alice), 100e18);
  }

  function test_RevertOnInsufficientBalance() public {
    vm.prank(alice);
    vm.expectRevert();
    token.transfer(owner, 1); // alice tiene 0
  }

  function test_EmitTransferEvent() public {
    vm.expectEmit(true, true, false, true);
    emit Transfer(owner, alice, 50e18);
    vm.prank(owner);
    token.transfer(alice, 50e18);
  }
}
$ forge test -vvv

Ventajas de Foundry vs Hardhat

🟢 Foundry: 10-100x más rápido · Fuzzing nativo · Solidity puro · forge-snapshot
🟡 Hardhat: Ecosystem JS maduro · ethers.js integrado · Plugins abundantes · TypeScript nativo
¦ Recomendación: usa Foundry para unit tests y Hardhat para deploy scripts e integración con frontend

Fuzz Testing ” Foundry encuentra bugs automáticamente

// Foundry ejecuta este test con 256+ inputs random
function testFuzz_Transfer(uint256 amount) public {
  // Bound limita el rango (evita overflow)
  amount = bound(amount, 0, 1_000_000e18);
  vm.prank(owner);
  token.transfer(alice, amount);
  assertEq(token.balanceOf(alice), amount);
  assertEq(
    token.balanceOf(owner),
    1_000_000e18 - amount
  );
}

// Invariant Test ” propiedad que siempre debe cumplirse
function invariant_TotalSupplyNeverChanges() public view {
  assertEq(token.totalSupply(), 1_000_000e18);
}

// foundry.toml ” Configuración de fuzzing
// [fuzz]
// runs = 1000
// seed = 0x3e8
// [invariant]
// runs = 50
// depth = 100  # Llamadas por run

Simulador de Fuzzing

Foundry ejecutará N runs con inputs aleatorios. Observa cuántos pasan.
256
$ forge test --match-test testFuzz
🧪 Ejecuta los tests en Hardhat o Foundry. Ambas herramientas son complementarias ” los mejores proyectos DeFi usan las dos.