Ana içeriğe geç

Waffle kütüphanesiyle basit bir akıllı sözleşmeyi test etme

akıllı sözleşmelersolidityWaffletest
Acemi
Ewa Kowalska
26 Şubat 2021
5 dakikalık okuma minute read

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;
2
3contract EtherSplitter {
4 address payable receiver1;
5 address payable receiver2;
6
7 event Transfer(address from, address to, uint256 amount);
8
9 constructor(address payable _address1, address payable _address2) public {
10 receiver1 = _address1;
11 receiver2 = _address2;
12 }
13
14 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öster
Kopyala

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"
5
6use(solidity)
7
8describe("Ether Splitter", () => {
9 const [sender, receiver1, receiver2] = new MockProvider().getWallets()
10 let splitter: Contract
11
12 beforeEach(async () => {
13 splitter = await deployContract(sender, EtherSplitter, [
14 receiver1.address,
15 receiver2.address,
16 ])
17 })
18
19 // add the tests here
20})
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 25
5 )
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})
6
7it("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:

Son düzenleme: @rooibos(opens in a new tab), 26 Şubat 2024

Bu rehber yararlı oldu mu?