Escribe tests que detectan bugs antes de desplegar ” porque en blockchain no hay "deshacer"
// 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); }); }); });
// 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); } }
// 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