Waffle kütüphanesiyle basit bir akıllı sözleşmeyi test etme
Bu öğreticide aşağıdakilerin nasıl yapılacağını öğreneceksiniz
- Cüzdan bakiyesindeki değişimleri test etme
- Belirtilen argümanlarla işlemlerin emisyonunu test etme
- Bir işlemin geri alındığını doğrulama
Varsayımlar
- Yeni bir JavaScript ya da TypeScript projesi oluşturabilirsiniz
- JavaScript'teki testlerle ilgili bazı basit deneyimleriniz mevcuttur
- Yarn ya da npm gibi bazı paket yöneticilerini daha önce kullandınız
- Akıllı sözleşmeler ve Solidity ile ilgili giriş seviyesinde bilgi sahibisiniz
Başlarken
Bu öğretici, yarn kullanarak test kurulumunu ve çalıştırmasını göstermektedir ancak npm tercihinde bulunmanız da sorun teşkil etmez. Resmi Waffle dokümanlarına(opens in a new tab) uygun referanslar sunacağım.
Bağımlılıkları Yükleme
Ethereum-waffle ve typescript bağımlılıklarını projenizin dev bağımlılıklarına ekleyin(opens in a new tab).
yarn add --dev ethereum-waffle ts-node typescript @types/jest
Örnek akıllı sözleşme
Öğretici boyunca basit bir akıllı sözleşme örneği olan EtherSplitter üzerinde çalışacağız. Bu, herhangi birinin belirli bir miktarda wei göndermesine ve bu miktarı önceden tanımlanmış iki alıcı arasında eşit olarak bölmesine izin vermenin haricinde pek bir şey yapmaz. Bölme işleminin gerçekleşmesi için wei sayısının çift olması gerekir, aksi takdirde işlem geri döner. Her iki alıcı için de, önce bir wei transferi ve ardından Transfer olayı gerçekleştirilir.
EtherSplitter kod parçasını src/EtherSplitter.sol
içine yerleştirin.
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, 'Uneven wei amount not allowed');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}Tümünü gösterKopyala
Sözleşmeyi derleme
Sözleşmeyi derlemek(opens in a new tab) için aşağıdaki girdiyi package.json dosyasına ekleyin:
1"scripts": {2 "build": "waffle"3 }Kopyala
Sonraki adım olarak, proje kök dizininde - waffle.json
- Waffle yapılandırma dosyasını oluşturun ve ardından aşağıdaki yapılandırmayı buraya yapıştırın:
1{2 "compilerType": "solcjs",3 "compilerVersion": "0.6.2",4 "sourceDirectory": "./src",5 "outputDirectory": "./build"6}Kopyala
yarn build
komutunu çalıştırın. Sonuç olarak, JSON formatında derlenmiş EtherSplitter sözleşmesinin bulunduğu build
dizini görünecektir.
Test kurulumu
Waffle ile test yapmak için Chai eşleştiricilerini ve Mocha'yı kullanmanız gerekeceğinden, bunları projenize eklemeniz(opens in a new tab) gerekir. Package.json dosyanızı güncelleyin ve komut dosyaları bölümüne test
girdisini ekleyin:
1"scripts": {2 "build": "waffle",3 "test": "export NODE_ENV=test && mocha -r ts-node/register 'test/**/*.test.ts'"4 }Kopyala
Eğer testlerinizi çalıştırmak(opens in a new tab) istiyorsanız, sadece yarn test
komutunu çalıştırmanız yeterlidir.
Test
Şimdi test
dizinini ve test\EtherSplitter.test.ts
yeni dosyasını oluşturun. Aşağıdaki kod parçasını kopyalayın ve test dosyanıza yapıştırın.
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("Ether Splitter", () => {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 // add the tests here20})Tümünü göster
Başlamadan önce bir kaç kelime. MockProvider
, blokzinciri taklit eden bir sürüm oluşturur. Ayrıca, EtherSplitter sözleşmesini test etmek için sahte cüzdanlar da sunar. Sağlayıcı üzerinde getWallets()
yöntemini çağırarak on cüzdana kadar cüzdan elde edebiliriz. Örnekte, üç tane gönderici için iki tane de alıcılar için cüzdan elde ediyoruz.
Sonraki adımda, "splitter" adında bir değişken tanımlıyoruz; bu, taklit EtherSplitter sözleşmemizdir. Bu, tek bir testin her yürütülmesinden önce deployContract
yöntemi ile oluşturulur. Bu yöntem, ilk parametre olarak aktarılan cüzdandan (bizim durumumuzda göndericinin cüzdanı) bir sözleşmenin dağıtımını simüle eder. İkinci parametre, test edilen sözleşmenin ABI'si ve bit kodudur; burada build
dizininden derlenmiş EtherSplitter sözleşmesinin json dosyasını aktarıyoruz. Üçüncü parametre, sözleşmenin oluşturucu argümanlarının bir dizisidir; bizim durumumuzda ise alıcıların iki adresidir.
changeBalances
İlk olarak, bölme yönteminin alıcıların cüzdan bakiyelerini gerçekten değiştirip değiştirmediğini kontrol edeceğiz. Eğer gönderen hesaptan 50 wei bölersek, her iki alıcının bakiyelerinin de 25 wei artmasını bekleriz. Waffle'ın changeBalances
eşleştiricisini kullanacağız:
1it("Changes accounts balances", async () => {2 await expect(() => splitter.split({ value: 50 })).to.changeBalances(3 [receiver1, receiver2],4 [25, 25]5 )6})
Eşleştiricinin ilk parametresi olarak alıcıların cüzdanlarının bir dizisini ve ikinci olarak da ilgili hesaplarda beklenen artışları içeren bir diziyi aktarırız. Eğer belirli bir cüzdanın bakiyesini kontrol etmek isteseydik, aşağıdaki örnekte olduğu gibi dizileri aktarmayı gerektirmeyen changeBalance
eşleştiricisini de kullanabilirdik:
1it("Changes account balance", async () => {2 await expect(() => splitter.split({ value: 50 })).to.changeBalance(3 receiver1,4 255 )6})
Hem changeBalance
hem de changeBalances
durumlarında, eşleştiricinin çağrıdan önceki ve sonraki bakiye durumuna erişmesi gerektiği için bölme işlevini bir geri çağrı olarak aktardığımızı unutmayın.
Sonra, her wei transferi sonrası Transfer olayının yayımlanıp yayımlanmadığını test ediyoruz. Waffle'daki başka bir eşleştiriciye geçeceğiz:
Emit
1it("Emits event on the transfer to the first receiver", async () => {2 await expect(splitter.split({ value: 50 }))3 .to.emit(splitter, "Transfer")4 .withArgs(sender.address, receiver1.address, 25)5})67it("Emits event on the transfer to the second receiver", async () => {8 await expect(splitter.split({ value: 50 }))9 .to.emit(splitter, "Transfer")10 .withArgs(sender.address, receiver2.address, 25)11})Tümünü göster
emit
eşleştiricisi, bir sözleşmenin bir yöntemi çağırırken bir etkinlik yayımlayıp yayımlamadığını kontrol etmemizi sağlar. emit
eşleştiricisinin parametreleri olarak, olayı yayımlayacağını tahmin ettiğimiz taklit sözleşmeyi ve bu olayın adını sağlıyoruz. Bizim durumumuzda, taklit sözleşme splitter
ve olayın adı Transfer
'dir. Ayrıca, olayın yayımlandığı sırada verilen argümanların kesin değerlerini de doğrulayabiliriz; withArgs
eşleştiricisine, olay bildirimi beklediğimiz sayıda argümanı aktarırız. EtherSplitter sözleşmesi durumunda ise, gönderici ve alıcının adresleri ile transfer edilen wei miktarını aktarırız.
revertedWith
Son örnek olarak, wei miktarının çift olmadığı durumlarda işlemin geri dönüp dönmediğini kontrol edeceğiz. revertedWith
eşleştiricisini kullanacağız:
1it("Reverts when Vei amount uneven", async () => {2 await expect(splitter.split({ value: 51 })).to.be.revertedWith(3 "Uneven wei amount not allowed"4 )5})
Eğer test başarılı olursa, işlemin gerçekten geri döndüğüne emin olacağız. Ancak require
ifadesine aktardığımız mesajlar ile revertedWith
içinde beklediğimiz mesaj arasında kesin bir eşleşme olmalıdır. EtherSplitter sözleşmesinin koduna geri dönersek, wei miktarı için require
ifadesine mesaj olarak "Tek wei miktarına izin verilmiyor" ifadesini giriyoruz. Bu, testimizde beklediğimiz mesajla eşleşir. Eğer eşit değillerse, test başarısız olacaktır.
Tebrikler!
Waffle ile akıllı sözleşmeleri test etmenin ilk büyük adımını tamamladınız! Diğer Waffle öğreticileri de ilginizi çekebilir:
- ERC20 sözleşmelerini Waffle ile test etme
- Waffle: Dinamik taklit ve sözleşme çağrılarını test etme
- Hardhat ve ethers ile Waffle'da merhaba dünya öğreticisi
Son düzenleme: @nhsz(opens in a new tab), 27 Şubat 2024