Blokkjede-smartkontrakter med Solidity · leksjon

Avansert testing med Foundry/Hardhat

Bruk avanserte funksjoner i testrammeverk som Foundry eller Hardhat for omfattende enhetstesting, integrasjonstesting og fuzz-testing.

Leksjon 1 av 411 trinn

Avansert testing med Foundry/Hardhat er en gratis leksjon i Blokkjede-smartkontrakter med Solidity på CoddyKit. Dette er leksjon 1 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Blokkjede-smartkontrakter med Solidity, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Blokkjede-smartkontrakter med Solidity inneholder totalt 4 leksjoner.

Introduksjon til avansert testing

Velkommen til avansert testing av smartkontrakter! Etter hvert som kontrakter blir mer komplekse, er ikke enkle enhetstester nok til å garantere robusthet.

Vi trenger kraftige strategier for å oppdage subtile feil og ivareta sikkerheten. I denne leksjonen ser vi nærmere på avanserte teknikker ved hjelp av rammeverk som Foundry eller Hardhat.

Hvorfor avansert testing er viktig

Grunnleggende tester kontrollerer forventet atferd, men hva med uventede inndata eller komplekse samhandlinger? Avansert testing hjelper med:

  • Grensetilfeller: Fuzz-testing kan finne inndata du ikke hadde forutsett.
  • Samhandling: Integrasjonstester bekrefter hvordan flere kontrakter fungerer sammen.
  • Sikkerhet: Avanserte metoder avdekker sårbarheter før utrulling.

Dette er avgjørende for å bygge robuste smartkontrakter.

Foundry: Ditt avanserte verktøysett

Selv om Hardhat er utmerket, skiller Foundry seg ut når du trenger virkelig avansert, Solidity-basert testing. Det er et lynraskt, portabelt og modulært verktøysett for utvikling av Ethereum-applikasjoner, skrevet i Rust.

Foundry bruker Solidity til å skrive tester, noe som gjør det svært intuitivt for utviklere av smartkontrakter.

Grundig gjennomgang av enhetstesting med Foundry

Enhetstester kontrollerer individuelle funksjoner isolert. Med Foundry skriver du tester direkte i Solidity, ofte ved å arve fra Test. La oss teste en enkel tellerkontrakt.

Legg merke til hvordan vi setter opp testmiljøet i setUp() før hver test.

pragma solidity ^0.8.0;

import "forge-std/Test.sol";

contract Counter {
    uint public count;

    function increment() public {
        count++;
    }

    function decrement() public {
        require(count > 0, "Count cannot be negative");
        count--;
    }
}

contract CounterTest is Test {
    Counter public counter;

    function setUp() public {
        counter = new Counter();
    }

    function test_Increment() public {
        counter.increment();
        assertEq(counter.count(), 1, "Count should be 1 after increment");
    }

    function test_Decrement() public {
        counter.increment(); // count is 1
        counter.decrement(); // count is 0
        assertEq(counter.count(), 0, "Count should be 0 after decrement");
    }

    function testFail_DecrementZero() public {
        // This test specifically expects a revert
        counter.decrement();
    }
}

Forstå integrasjonstesting

Integrasjonstester bekrefter samhandlingen mellom flere smartkontrakter eller mellom en kontrakt og eksterne tjenester, for eksempel orakler. De sikrer at ulike komponenter fungerer harmonisk sammen.

Dette er avgjørende fordi individuelle kontrakter kan være feilfrie, mens den samlede logikken kan introdusere problemer.

Eksempel på integrasjonstest (Foundry)

La oss simulere et scenario der en Token-kontrakt samhandler med en Vault-kontrakt. Hvelvet lar brukere sette inn og ta ut tokens.

Integrasjonstesten vår kontrollerer om tokens overføres korrekt mellom dem, og om brukersaldoene oppdateres.

pragma solidity ^0.8.0;

import "forge-std/Test.sol";
import "forge-std/console.sol";

contract MyToken {
    mapping(address => uint) public balances;

    constructor() {
        balances[msg.sender] = 1000;
    }

    function transfer(address to, uint amount) public returns (bool) {
        require(balances[msg.sender] >= amount, "Insufficient balance");
        balances[msg.sender] -= amount;
        balances[to] += amount;
        return true;
    }
}

contract Vault {
    MyToken public token;
    mapping(address => uint) public deposits;

    constructor(address _token) {
        token = MyToken(_token);
    }

    function deposit(uint amount) public {
        // Assume token.transferFrom or approval for real world. 
        // Simplified here for demo to show interaction.
        token.transfer(address(this), amount); 
        deposits[msg.sender] += amount;
    }

    function withdraw(uint amount) public {
        require(deposits[msg.sender] >= amount, "Insufficient deposit");
        deposits[msg.sender] -= amount;
        token.transfer(msg.sender, amount); 
    }
}

contract IntegrationTest is Test {
    MyToken public token;
    Vault public vault;

    address public ALICE = makeAddr("alice");

    function setUp() public {
        token = new MyToken();
        vault = new Vault(address(token));

        // Give ALICE some tokens for testing from initial deployer
        vm.startPrank(address(this));
        token.transfer(ALICE, 500); 
        vm.stopPrank();
    }

    function test_AliceDepositsAndWithdraws() public {
        vm.startPrank(ALICE);
        
        uint initialAliceBalance = token.balances(ALICE);
        uint depositAmount = 100;

        // Alice deposits
        token.transfer(address(vault), depositAmount); 
        vault.deposit(depositAmount); 

        assertEq(token.balances(ALICE), initialAliceBalance - depositAmount, "Alice's balance should decrease");
        assertEq(token.balances(address(vault)), depositAmount, "Vault should hold deposit amount");
        assertEq(vault.deposits(ALICE), depositAmount, "Alice's vault deposit should be recorded");

        // Alice withdraws
        vault.withdraw(depositAmount);
        assertEq(token.balances(ALICE), initialAliceBalance, "Alice's balance should be restored");
        assertEq(token.balances(address(vault)), 0, "Vault should be empty");
        assertEq(vault.deposits(ALICE), 0, "Alice's vault deposit should be zero");

        vm.stopPrank();
    }
}

Fuzz-testing: Oppdagelse av grensetilfeller

Fuzz-testing (eller fuzzing) genererer automatisk tilfeldige og uventede inndata til funksjonene dine. I stedet for at du gjetter deg frem til grensetilfeller, prøver fuzzeren millioner av kombinasjoner.

Dette er svært effektivt for å finne sårbarheter som heltallsoverflyt, underflyt eller uventede reverseringer som manuelle tester kan overse.

Fuzz-testing i praksis (Foundry)

Med Foundry er fuzzing innebygd. Bare legg til parametere i testfunksjonen! Foundry genererer automatisk tilfeldige verdier for a og b innenfor rimelige områder.

Dette bidrar til å sikre at funksjonene våre håndterer ulike inndata korrekt, særlig når vi kontrollerer uventet atferd som overflyt eller underflyt.

pragma solidity ^0.8.0;

import "forge-std/Test.sol";

contract Calculator {
    function add(uint a, uint b) public pure returns (uint) {
        return a + b;
    }

    function subtract(uint a, uint b) public pure returns (uint) {
        require(a >= b, "Cannot subtract more than available");
        return a - b;
    }
}

contract FuzzTest is Test {
    Calculator public calculator;

    function setUp() public {
        calculator = new Calculator();
    }

    // Fuzz test for addition: check if a + b >= a (unless overflow)
    function testFuzz_Add(uint a, uint b) public {
        // Note: For real-world, use SafeMath or explicit checks for overflows.
        // This test implicitly relies on default Solidity overflow behavior.
        uint sum = calculator.add(a, b);
        // If no overflow, sum should be >= a
        if (sum < a) {
            // Overflow occurred
            assertTrue(a > type(uint).max - b, "Expected overflow");
        } else {
            assertTrue(sum >= a, "Sum should be greater than or equal to a");
        }
    }

    // Fuzz test for subtraction: ensure result is always <= a
    function testFuzz_Subtract(uint a, uint b) public {
        // Only run if a >= b to avoid expected reverts from 'require'
        vm.assume(a >= b);
        uint result = calculator.subtract(a, b);
        assertTrue(result <= a, "Result should be less than or equal to a");
    }
}

Egenskapsbasert testing (PBT)

Fuzz-testing er en kraftig form for egenskapsbasert testing (PBT). I stedet for å teste bestemte eksempler definerer PBT egenskaper (invarianter) som alltid skal være oppfylt av koden.

Fuzzeren genererer deretter inndata for å forsøke å bryte disse egenskapene. Denne tilnærmingen gir mer robuste og mindre skjøre tester, og identifiserer grensetilfeller du kanskje aldri ville ha tenkt på manuelt.

Test kunnskapene dine

Hvilke av følgende påstander om avanserte teknikker for testing av smartkontrakter er SANNE?

Oppsummering: Avansert testing

Du har utforsket verdenen av avansert testing av smartkontrakter!

  • Vi gikk videre enn grunnleggende enhetstester for å håndtere komplekse scenarier.
  • Foundry tilbyr kraftige verktøy for Solidity-basert testing.
  • Enhetstester bekrefter individuelle komponenter.
  • Integrasjonstester sikrer at flere kontrakter fungerer sammen.
  • Fuzz-testing og egenskapsbasert testing bidrar til å oppdage skjulte feil ved å generere tilfeldige inndata og kontrollere invarianter.

Det er avgjørende å beherske disse teknikkene for å kunne rulle ut sikre og pålitelige smartkontrakter.

Gratis å komme i gang

Lær deg Blokkjede-smartkontrakter med Solidity med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
12
Leksjoner
48

Ofte stilte spørsmål

Er leksjonen «Avansert testing med Foundry/Hardhat» gratis?

Ja – hele teksten i «Avansert testing med Foundry/Hardhat» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av Blokkjede-smartkontrakter med Solidity-kurset, kan du oppgradere til CoddyKit PRO. Kurset i Blokkjede-smartkontrakter med Solidity inneholder totalt 4 leksjoner.

Hva lærer jeg i «Avansert testing med Foundry/Hardhat»?

Bruk avanserte funksjoner i testrammeverk som Foundry eller Hardhat for omfattende enhetstesting, integrasjonstesting og fuzz-testing. Du øver på Blokkjede-smartkontrakter med Solidity med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Blokkjede-smartkontrakter med Solidity?

Ingen tidligere erfaring er nødvendig. Blokkjede-smartkontrakter med Solidity på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 1 av 4.

Hvor lang tid tar leksjonen «Avansert testing med Foundry/Hardhat»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Blokkjede-smartkontrakter med Solidity-leksjonen?

Ja. Alle Blokkjede-smartkontrakter med Solidity-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Avansert testing med Foundry/Hardhat
  2. Grunnleggende om formell verifikasjon
  3. Distribusjon og overvåking på mainnet
  4. Fuzzing og invarianttesting
← Tilbake til Blokkjede-smartkontrakter med Solidity