Ana içeriğe geç

Solidity akıllı sözleşmeleri test etmek için nasıl taklit edilir?

solidityakıllı kontratlartest etmektaklit etme
Orta düzey
Markus Waas
soliditydeveloper.com(opens in a new tab)
2 Mayıs 2020
3 dakikalık okuma minute read

Taklit nesneler(opens in a new tab) nesne yönelimli programlamada yaygın kullanılan bir tasarım modelidir. Fransızca'dan gelen "mocquer" kelimesi "dalga geçmek" anlamındadır. Bu kelime "gerçek olan bir şeyi taklit etmek" anlamına evrilmiştir ki bu, tam olarak programlamada yaptığımız şeydir. Akıllı sözleşmelerinizle lütfen sadece istediğiniz zaman dalga geçin ama her boş vaktinizde onları taklit edin. Bu, hayatınızı kolaylaştıracak.

Sözleşmelere taklit yoluyla birim testi uygulama

Bir sözleşmeyi taklit etmek, sözleşmenin gerçek hali gibi davranan ve geliştirici tarafından kolayca kontrol edilebilen ikinci bir versiyonunu oluşturmak anlamına gelir. Genelde sözleşmenin ufak bir bölümüne birim testi yapmak istediğiniz karmaşık sözleşmelerle karşılaşırsınız. Buradaki sorun, ya bu ufak parçanın test edilmesi çok detaylı bir sözleşme durumu gerektiriyorsa ve buna ulaşmak zorsa?

Her seferinde sözleşmeyi istenen duruma getiren karmaşık bir test yazabilir veya "taklitlerle" işinizi kolayca halledebilirsiniz. Bir sözleşme, kalıtım yöntemiyle kolayca taklit edilebilir. Orijinal sözleşmeyi içeren ikinci bir taklit sözleşme yazın. Şimdi fonksiyonları taklit sözleşmeniz için geçersiz kılabilirsiniz. Bir örnekle görelim.

Örnek: Özel ERC20

Başlangıç özel zamanı olan örnek bir ERC-20 sözleşmesi kullanıyoruz. Sözleşmenin sahibi özel kullanıcıları yönetebilir ve başlangıçta yalnızca bu kullanıcıların jeton almasına izin verir. Belirli bir zaman geçtikten sonra herkes jetonları kullanabilecektir. Eğer merak ediyorsanız, OpenZeppelin sözleşmeleri v3 dahilindeki _beforeTokenTransfer(opens in a new tab)'i kullanıyoruz.

1pragma solidity ^0.6.0;
2
3import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
4import "@openzeppelin/contracts/access/Ownable.sol";
5
6contract PrivateERC20 is ERC20, Ownable {
7 mapping (address => bool) public isPrivateUser;
8 uint256 private publicAfterTime;
9
10 constructor(uint256 privateERC20timeInSec) ERC20("PrivateERC20", "PRIV") public {
11 publicAfterTime = now + privateERC20timeInSec;
12 }
13
14 function addUser(address user) external onlyOwner {
15 isPrivateUser[user] = true;
16 }
17
18 function isPublic() public view returns (bool) {
19 return now >= publicAfterTime;
20 }
21
22 function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override {
23 super._beforeTokenTransfer(from, to, amount);
24
25 require(_validRecipient(to), "PrivateERC20: invalid recipient");
26 }
27
28 function _validRecipient(address to) private view returns (bool) {
29 if (isPublic()) {
30 return true;
31 }
32
33 return isPrivateUser[to];
34 }
35}
Tümünü göster
Kopyala

Şimdi sözleşmeyi taklit edelim.

1pragma solidity ^0.6.0;
2import "../PrivateERC20.sol";
3
4contract PrivateERC20Mock is PrivateERC20 {
5 bool isPublicConfig;
6
7 constructor() public PrivateERC20(0) {}
8
9 function setIsPublic(bool isPublic) external {
10 isPublicConfig = isPublic;
11 }
12
13 function isPublic() public view returns (bool) {
14 return isPublicConfig;
15 }
16}
Tümünü göster
Kopyala

Şu hata mesajlarından birini alacaksınız:

  • PrivateERC20Mock.sol: TypeError: Overriding function is missing "override" specifier.
  • PrivateERC20.sol: TypeError: Trying to override non-virtual function. Did you forget to add "virtual"?.

Yeni 0.6 Solidity sürümünü kullandığımızdan geçersiz kılınabilecek fonksiyonlar için virtual anahtar kelimesini ve geçersiz kılma fonksiyonu için geçersiz kıl kelimesini eklememiz gerekir. Şimdi bunları her iki isPublic fonksiyonuna ekleyelim.

Artık birim testlerinizde bunun yerine PrivateERC20Mock kullanabilirsiniz. Özel kullanım zamanlarında nasıl tepki vereceğini test etmek isterseniz, setIsPublic(false) komutunu ve setIsPublic(true) komutunu da genel kullanım zamanını test etmek için kullanabilirsiniz. Elbette bizim örneğimizde, zamanları buna göre değiştirmek için zaman yardımcılarını(opens in a new tab) da kullanabiliriz. Ancak taklit amacı artık açık olmalıdır ve bunun sadece zamanı ilerletmek kadar kolay olmadığı durumları hayal edebilirsiniz.

Çok sayıda sözleşmeyi taklit etme

Her taklit için ayrı bir sözleşme oluşturmak karışıklık oluşturabilir. Eğer bu sizi rahatsız ediyorsa, MockContract(opens in a new tab) kütüphanesine bakabilirsiniz. Size anlık olarak sözleşmelerin davranışlarını değiştirme ve geçersiz kılma olanağı sağlar. Ancak, yalnızca diğer bir sözleşmeye yapılan taklitler için çalışır; bu nedenle, örneğimizde işe yaramaz.

Taklit etme, daha da güçlü olabilir

Taklit etmenin gücü burada bitmiyor.

  • Fonksiyon ekleme: Sadece belirli bir işlevi geçersiz kılmak açısından değil, aynı zamanda ilave fonksiyonlar eklemek açısından da kullanışlıdır. Jetonlar için iyi bir örnek, herhangi bir kullanıcının ücretsiz olarak yeni jetonlar almasına izin vermek için ek bir mint işlevine sahip olmaktır.
  • Test ağlarında kullanım: Sözleşmelerinizi merkeziyetsiz uygulamalarınızla birlikte test ağlarına dağıtıp test ettiğinizde, taklit sürümlerini kullanmayı düşünün. Mecbur kalmadıkça fonksiyonları geçersiz kılmaktan kaçının. Sonuçta arkasındaki gerçek mantığı test etmek istiyorsunuz. Fakat örneğin, sözleşme durumunu en başa sıfırlayan ve yeni bir dağıtım gerektirmeyen bir sıfırlama işlevi eklemek de yararlı olabilir. Tabii ki de bunu bir Ana Ağ sözleşmesinde kullanmak istemezsiniz.

Son düzenleme: @mergenether(opens in a new tab), 23 Kasım 2023

Bu rehber yararlı oldu mu?