Testování jednoduchého chytrého kontraktu s knihovnou Waffle
V tomto návodu se naučíte, jak
- Testovat změny zůstatku peněženky
- Testovat emisi událostí se zadanými argumenty
- Ověřit, že byla transakce vrácena
Předpoklady
- Můžete vytvořit nový projekt v JavaScriptu nebo TypeScriptu
- Máte nějaké základní zkušenosti s testy v JavaScriptu
- Použili jste nějaké správce balíčků jako yarn nebo npm
- Máte velmi základní znalosti chytrých kontraktů a Solidity
Začínáme
Tento návod ukazuje nastavení a spuštění testu pomocí yarn, ale není problém, pokud dáváte přednost npm – poskytnu správné odkazy na oficiální dokumentaciopens in a new tab Waffle.
Instalace závislostí
Přidejteopens in a new tab závislosti ethereum-waffle a typescript do vývojářských závislostí vašeho projektu.
yarn add --dev ethereum-waffle ts-node typescript @types/jestPříklad chytrého kontraktu
Během tohoto návodu budeme pracovat na jednoduchém příkladu chytrého kontraktu – EtherSplitter. Nedělá toho moc kromě toho, že umožňuje komukoli poslat nějaké wei a rovnoměrně je rozdělit mezi dva předdefinované příjemce.
Funkce split vyžaduje, aby byl počet wei sudý, jinak se vrátí zpět. Pro oba příjemce provádí převod wei následovaný emisí události Transfer.
Vložte úryvek kódu EtherSplitter do src/EtherSplitter.sol.
1pragma solidity ^0.6.0;23contract EtherSplitter {4 address payable receiver1;5 address payable receiver2;67 event Transfer(address from, address to, uint256 amount);89 constructor(address payable _address1, address payable _address2) public {10 receiver1 = _address1;11 receiver2 = _address2;12 }1314 function split() public payable {15 require(msg.value % 2 == 0, 'Lichá částka wei není povolena');16 receiver1.transfer(msg.value / 2);17 emit Transfer(msg.sender, receiver1, msg.value / 2);18 receiver2.transfer(msg.value / 2);19 emit Transfer(msg.sender, receiver2, msg.value / 2);20 }21}Zobrazit všeKompilace kontraktu
Pro kompilaciopens in a new tab kontraktu přidejte následující položku do souboru package.json:
1"scripts": {2 "build": "waffle"3 }Dále vytvořte konfigurační soubor Waffle v kořenovém adresáři projektu – waffle.json – a poté tam vložte následující konfiguraci:
1{2 "compilerType": "solcjs",3 "compilerVersion": "0.6.2",4 "sourceDirectory": "./src",5 "outputDirectory": "./build"6}Spusťte yarn build. Výsledkem je, že se objeví adresář build s kompilovaným kontraktem EtherSplitter ve formátu JSON.
Nastavení testu
Testování pomocí Waffle vyžaduje použití Chai matchers a Mocha, takže je musíte přidatopens in a new tab do svého projektu. Aktualizujte soubor package.json a přidejte položku test do části se skripty:
1"scripts": {2 "build": "waffle",3 "test": "export NODE_ENV=test && mocha -r ts-node/register 'test/**/*.test.ts'"4 }Chcete-li spustitopens in a new tab své testy, stačí spustit yarn test .
Testování
Nyní vytvořte adresář test a vytvořte nový soubor test\EtherSplitter.test.ts.
Zkopírujte úryvek níže a vložte jej do našeho testovacího souboru.
1import { expect, use } from "chai"2import { Contract } from "ethers"3import { deployContract, MockProvider, solidity } from "ethereum-waffle"4import EtherSplitter from "../build/EtherSplitter.json"56use(solidity)78describe("Rozdělovač etheru", () => {9 const [sender, receiver1, receiver2] = new MockProvider().getWallets()10 let splitter: Contract1112 beforeEach(async () => {13 splitter = await deployContract(sender, EtherSplitter, [14 receiver1.address,15 receiver2.address,16 ])17 })1819 // sem přidejte testy20})Zobrazit všePár slov na úvod.
MockProvider poskytuje testovací verzi blockchainu. Poskytuje také testovací peněženky, které nám poslouží k testování kontraktu EtherSplitter. Můžeme získat až deset peněženek zavoláním metody getWallets() na providera. V příkladu získáme tři peněženky – pro odesílatele a pro dva příjemce.
Dále deklarujeme proměnnou nazvanou „splitter“ – to je náš testovací kontrakt EtherSplitter. Vytváří se před každým spuštěním jednotlivého testu metodou deployContract. Tato metoda simuluje nasazení kontraktu z peněženky předané jako první parametr (v našem případě peněženky odesílatele). Druhým parametrem je ABI a bytecode testovaného kontraktu – předáme tam soubor json zkompilovaného kontraktu EtherSplitter z adresáře build. Třetím parametrem je pole s argumenty konstruktoru kontraktu, což jsou v našem případě dvě adresy příjemců.
changeBalances
Nejprve zkontrolujeme, zda metoda split skutečně změní zůstatky v peněženkách příjemců. Pokud rozdělíme 50 wei z účtu odesílatele, očekávali bychom, že zůstatky obou příjemců se zvýší o 25 wei. Použijeme matcher changeBalances od Waffle:
1it("Změní zůstatky účtů", async () => {2 await expect(() => splitter.split({ value: 50 })).to.changeBalances(3 [receiver1, receiver2],4 [25, 25]5 )6})Jako první parametr matcheru předáváme pole peněženek příjemců a jako druhý – pole očekávaných navýšení na odpovídajících účtech.
Pokud bychom chtěli zkontrolovat zůstatek jedné konkrétní peněženky, mohli bychom také použít matcher changeBalance, který nevyžaduje předávání polí, jako v příkladu níže:
1it("Změní zůstatek účtu", async () => {2 await expect(() => splitter.split({ value: 50 })).to.changeBalance(3 receiver1,4 255 )6})Všimněte si, že v obou případech changeBalance a changeBalances předáváme funkci split jako callback, protože matcher potřebuje přístup ke stavu zůstatků před a po volání.
Dále otestujeme, zda byla po každém převodu wei emitována událost Transfer. Obrátíme se na další matcher od Waffle:
Emit
1it("Emituje událost při převodu na prvního příjemce", async () => {2 await expect(splitter.split({ value: 50 }))3 .to.emit(splitter, "Transfer")4 .withArgs(sender.address, receiver1.address, 25)5})67it("Emituje událost při převodu na druhého příjemce", async () => {8 await expect(splitter.split({ value: 50 }))9 .to.emit(splitter, "Transfer")10 .withArgs(sender.address, receiver2.address, 25)11})Zobrazit všeMatcher emit nám umožňuje zkontrolovat, zda kontrakt emitoval událost při volání metody. Jako parametry matcheru emit poskytneme testovací kontrakt, u kterého předpokládáme emisi události, spolu s názvem této události. V našem případě je testovacím kontraktem splitter a název události – Transfer. Můžeme také ověřit přesné hodnoty argumentů, se kterými byla událost emitována – do matcheru withArgs předáme tolik argumentů, kolik naše deklarace události očekává. V případě kontraktu EtherSplitter předáváme adresy odesílatele a příjemce spolu s převedenou částkou wei.
revertedWith
Jako poslední příklad zkontrolujeme, zda byla transakce vrácena v případě lichého počtu wei. Použijeme matcher revertedWith:
1it("Vrátí zpět, když je částka wei lichá", async () => {2 await expect(splitter.split({ value: 51 })).to.be.revertedWith(3 "Lichá částka wei není povolena"4 )5})Test, pokud projde, nás ujistí, že transakce byla skutečně vrácena. Musí však také existovat přesná shoda mezi zprávami, které jsme předali v příkazu require, a zprávou, kterou očekáváme v revertedWith. Pokud se vrátíme ke kódu kontraktu EtherSplitter, v příkazu require pro částku wei poskytujeme zprávu: ‚Lichá částka wei není povolena‘. Ta se shoduje se zprávou, kterou očekáváme v našem testu. Pokud by se neshodovaly, test by selhal.
Gratulujeme!
Udělali jste první velký krok k testování chytrých kontraktů s Waffle!
Stránka naposledy aktualizována: 14. února 2026