Lompat ke konten utama

Cara melakukan mock pada smart contract Solidity untuk pengujian

Solidity
smart contract
pengujian
mocking
Menengah
Markus Waas
2 Mei 2020
4 menit baca

Objek mock (opens in a new tab) adalah pola desain yang umum dalam pemrograman berorientasi objek. Berasal dari kata bahasa Prancis kuno 'mocquer' yang berarti 'mengolok-olok', kata ini berevolusi menjadi 'meniru sesuatu yang nyata' yang sebenarnya merupakan apa yang kita lakukan dalam pemrograman. Silakan mengolok-olok kontrak pintar Anda jika Anda mau, tetapi lakukan mock pada kontrak tersebut kapan pun Anda bisa. Hal ini akan membuat hidup Anda lebih mudah.

Pengujian unit kontrak dengan mock

Melakukan mock pada sebuah kontrak pada dasarnya berarti membuat versi kedua dari kontrak tersebut yang berperilaku sangat mirip dengan aslinya, tetapi dengan cara yang dapat dikontrol dengan mudah oleh pengembang. Anda sering kali berakhir dengan kontrak yang kompleks di mana Anda hanya ingin melakukan pengujian unit pada bagian-bagian kecil dari kontrak. Masalahnya adalah bagaimana jika pengujian bagian kecil ini memerlukan state kontrak yang sangat spesifik yang sulit untuk dicapai?

Anda dapat menulis logika penyiapan pengujian yang kompleks setiap kali yang membawa kontrak ke dalam state yang diperlukan atau Anda menulis sebuah mock. Melakukan mock pada sebuah kontrak itu mudah dengan pewarisan (inheritance). Cukup buat kontrak mock kedua yang mewarisi dari kontrak aslinya. Sekarang Anda dapat menimpa (override) fungsi ke mock Anda. Mari kita lihat dengan sebuah contoh.

Contoh: ERC-20 Privat

Kita menggunakan contoh kontrak ERC-20 yang memiliki waktu privat awal. Pemilik dapat mengelola pengguna privat dan hanya mereka yang akan diizinkan untuk menerima token pada awalnya. Setelah waktu tertentu berlalu, semua orang akan diizinkan untuk menggunakan token tersebut. Jika Anda penasaran, kita menggunakan hook _beforeTokenTransfer (opens in a new tab) dari kontrak OpenZeppelin v3 yang baru.

Dan sekarang mari kita lakukan mock.

Anda akan mendapatkan salah satu pesan kesalahan berikut:

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

Karena kita menggunakan versi Solidity 0.6 yang baru, kita harus menambahkan kata kunci virtual untuk fungsi yang dapat ditimpa dan override untuk fungsi yang menimpa. Jadi mari kita tambahkan keduanya ke kedua fungsi isPublic.

Sekarang dalam pengujian unit Anda, Anda dapat menggunakan PrivateERC20Mock sebagai gantinya. Ketika Anda ingin menguji perilaku selama waktu penggunaan privat, gunakan setIsPublic(false) dan demikian pula setIsPublic(true) untuk menguji waktu penggunaan publik. Tentu saja dalam contoh kita, kita bisa saja menggunakan pembantu waktu (opens in a new tab) untuk mengubah waktu yang sesuai juga. Tetapi gagasan tentang mocking seharusnya sudah jelas sekarang dan Anda dapat membayangkan skenario di mana hal itu tidak semudah sekadar memajukan waktu.

Melakukan mock pada banyak kontrak

Ini bisa menjadi berantakan jika Anda harus membuat kontrak lain untuk setiap mock. Jika ini mengganggu Anda, Anda dapat melihat Pustaka MockContract (opens in a new tab). Pustaka ini memungkinkan Anda untuk menimpa dan mengubah perilaku kontrak secara langsung (on-the-fly). Namun, ini hanya berfungsi untuk melakukan mock pada panggilan ke kontrak lain, sehingga tidak akan berfungsi untuk contoh kita.

Mocking bisa menjadi lebih tangguh

Kekuatan mocking tidak berakhir di situ.

  • Menambahkan fungsi: Tidak hanya menimpa fungsi tertentu yang berguna, tetapi juga sekadar menambahkan fungsi tambahan. Contoh yang baik untuk token adalah dengan memiliki fungsi mint tambahan untuk memungkinkan pengguna mana pun mendapatkan token baru secara gratis.
  • Penggunaan di testnet: Saat Anda menyebarkan dan menguji kontrak Anda di testnet bersama dengan aplikasi terdesentralisasi (dapp) Anda, pertimbangkan untuk menggunakan versi yang di-mock. Hindari menimpa fungsi kecuali Anda benar-benar harus melakukannya. Bagaimanapun juga, Anda ingin menguji logika yang sebenarnya. Tetapi menambahkan misalnya fungsi reset bisa berguna yang hanya mengatur ulang state kontrak ke awal, tidak diperlukan penyebaran baru. Jelas Anda tidak ingin memiliki itu dalam kontrak Mainnet.