Python Unit Testing dengan Mocking

Dalam pengembangan suatu perangkat lunak dengan skala yang besar, kerap kali kita menggunakan API service / library yang telah dikembangkan untuk mempermudah proses development aplikasi. Akan tetapi, terkadang kita mengalami kesulitan untuk membuat unit test terhadap suatu fungsi yang memakai service / library tersebut karena output dari service / library tersebut tidak deterministik.
Mungkin terbesit di pikiran kita untuk menyerah membuat unit test dari fungsi tersebut dan mempercayai bahwa implementasi fungsi tersebut sudah tepat. Akan tetapi, sebagai developer kita jangan menyerah dengan tantangan tersebut, Ada sebuah tools yang dapat digunakan untuk menghadapi masalah tersebut, yaitu Mocking.
Mocking
Mocking adalah sebuah konsep di mana sebuah implementasi fungsi digantikan dengan sebuah fungsi imitasi yang outputnya sudah ditentukan oleh developer dan output tersebut sudah dianggap benar. Mocking biasa digunakan untuk menggantikan sebuah fungsi yang sulit untuk dilakukan tes karena sifat non-deterministiknya, seperti API service.
Berikut contoh kasus di mana mocking dibutuhkan.
- Fungsi A adalah fungsi dari sebuah service dari sebuah API. Kita mengetahui fungsi ini sudah dapat berjalan dengan lancar dan mengetahui semua output dari fungsi ini. Akan tetapi, kita tidak mengetahui pasangan input dan output dari fungsi.
- Fungsi B menggunakan Fungsi A dalam implementasinya.
Fungsi A tidak memerlukan unit testing karena fungsi tersebut merupakan fungsi yang berasal dari fungsi service dari sebuah API, sedangkan fungsi B memerlukan unit testing karena fungsi ini merupakan fungsi yang kita implementasikan sendiri.
Dalam kasus ini, kita perlu melakukan mocking fungsi A saat membuat unit testing untuk fungsi B. Kita membuat fungsi mock dari fungsi A yang mengeluarkan output dan dianggap benar oleh developer dan meng-override fungsi yang asli sehingga memudahkan developer untuk fokus pada pembuatan unit test pada fungsi B.
Sebenarnya Mocking sendiri tidak terabatas untuk fungsi saja, Object Class juga dapat dibuat Mock-nya. Tetapi dalam artikel ini, Saya memfokuskan pada Mocking sebuah fungsi.
Implementasi Mocking dalam Python.
Code di bawah ini merupakan fungsi yang melakukan validasi sebuah access token dari google oauth dengan mengirimkan access token ke service google. Jika access token benar, service google akan mengirimkan JSON yang berisi data email pengguna dari access token tersebut.
Dari fungsi di atas, saya melakukan mocking pada fungsi requests.get karena saya sulit untuk menentukan access_token yang valid untuk dikirimkan ke service google dan fungsi json.loads untuk yang mengemulasi proses decoding dari JSON yang diterima oleh sistem dari proses request dengan output yang sudah ditentukan.
Saya hanya perlu menambahkan decorator @patch pada fungsi unit test dengan parameter “module.fungsi” sesuai dengan fungsi yang ingin di-mock (contoh : @patch(‘validate_google_token.requests.get’)).
Lalu kita harus menambahkan parameter mock object pada fungsi unit test tersebut. urutan parameter mock object sesuai dengan urutan decorator @patch yang terdekat dengan fungsi unit test.
Lalu untuk mengatur output fungsi mock dengan mengatur atribut mock object di dalam fungsi unit test. Atribut untuk mensimulasikan suatu fungsi adalah atribut return_value yang nilainya akan dikembalikan apabila mock object dipanggil sebagai fungsi. return_value juga dapat mengembalikan mock object baru dengan mengatur atribut dari return_value tersebut (contoh: mock_get.return_value.text = “DKSJNDKDSKN”)
Kesimpulan
Mocking merupakan tools yang sangat mempermudah pembuatan unit test. Mocking dapat memanipulasi output dari suatu fungsi yang diimplementasikan pada suatu fungsi sesuai yang apa yang diinginkan programmer. Hal ini memudahkan developer untuk fokus pada pembuatan unit test pada implementasi suatu fungsi tanpa perlu memikirkan output dari fungsi yang dimplementasikan di dalamnya.