hamonangann / hamonangann.github.io

https://hamonangann.github.io/
Creative Commons Attribution Share Alike 4.0 International
0 stars 0 forks source link

Test-Driven Development dengan Git #3

Closed hamonangann closed 1 year ago

hamonangann commented 1 year ago

Pada artikel kali ini, kita akan menerapkan paradigma pengembangan perangkat lunak Test Driven Development (TDD) dan mengintegrasikannya dengan Git, tool yang digunakan untuk memantau kode program.

Aturan Main

Sebelum memulai praktik kita perlu mengetahui proses dalam TDD. Kent Beck, seorang pengembang perangkat lunak yang juga mencetuskan Extreme Programming (XP), menulis demikian pada bukunya yang berjudul "Test Driven Development by Example":

  1. Quickly add a test
  2. Run all tests and see the new one fail
  3. Make a little change
  4. Run all tests and see them all succeed
  5. Refactor to remove duplication

Kita akan terus-menerus mengulangi langkah di atas. Perbedaan praktik dalam TDD dengan yang tidak pakai TDD adalah kode tes harus dibuat lebih dulu sebelum kode solusi.

Selain itu Uncle Bob juga mengajukan tiga aturan dalam menjalankan TDD:

  1. You are not allowed to write any production code unless it is to make a failing unit test pass.
  2. You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
  3. You are not allowed to write any more production code than is sufficient to pass the one failing unit test.

Intinya, TDD yang benar harus dijalankan satu per satu. Buat satu tes, disusul solusi untuk menyelesaikan satu tes tersebut. Setiap langkah perlu diverifikasi. Kode tes harus selesai dibuat tepat setelah kode tersebut menghasilkan kegagalan (ini menjamin hanya 1 assertion saja yang dibuat). Kode solusi cukup untuk menyelesaikan 1 test tersebut. Setelah solusi berhasil mengubah 1 assertion menjadi sukses, buat lagi tes/assertion lainnya.

Keuntungan TDD

Menurut saya, TDD membuat developer terus-menerus menguji kodenya sehingga program yang dibuat betul-betul bisa dipahami behaviournya.

Integrasi dengan Git

Untuk menerapkan TDD pada kode yang dipantau dengan Git, kita bisa melakukan hal-hal berikut:

  1. Pastikan file untuk kode tes dan file untuk kode solusi terpisah
  2. Lakukan commit untuk kode tes dan commit untuk kode solusi secara terpisah

Sama seperti pada umumnya, satu commit idealnya untuk satu pekerjaan. Dari daftar ini kita dapat menjadikan [test] untuk kode tes dan [feat] untuk kode solusi. Jadi gara-gara pakai TDD, tidak harus setiap satu tes atau assertion dibuat commit tersendiri.

Langsung saja kita praktikkan

Praktik: Instalasi

Kita akan menggunakan Python dan Git. Keduanya dapat diinstalasi dengan panduan di bawah:

Praktik: Memulai Git Repository

Untuk memulai proyek, siapkan folder bernama praktik-tdd-git. Jalankan kedua line dibawah pada terminal/CMD:

mkdir praktik-tdd-git
cd praktik-tdd-git

Buat dua file Python bernama main.py dan test.py, lalu lakukan perintah git add -A pada terminal/CMD. Pastikan kedua file muncul pada new file:

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   main.py
        new file:   test.py

Setelah itu lakukan git commit -m "initial commit" untuk melakukan commit pertama. Pastikan kedua file termasuk dalam change (nomor setelah create mode dapat diabaikan)

 2 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 praktik-tdd-git/main.py
 create mode 100644 praktik-tdd-git/test.py

Kita akan melakukan git add dan git commit lagi nanti.

Praktik: Membuat Unit Test

Kita akan membuat fungsi nilai faktorial:

  1. Fungsi menerima sebuah teks input dan mengembalikan sebuah teks output
  2. Jika input bukan numerik (mengandung karakter selain 0-9) program mengembalikan string Harap masukkan input numerik (0-9)
  3. Jika input numerik, program mengembalikan Nilai faktorialnya adalah {x} dengan x adalah nilai faktorial dari input. Misalnya, nilai faktorial 4 adalah 1x2x3x4=24 sehingga outputnya adalah Nilai faktorialnya adalah 24.

Karena kita menerapkan TDD, kita buat terlebih dahulu unit testnya. Buka test.py dan tuliskan kode berikut:

import unittest

class TestFaktorial(unittest.TestCase):
    # We will implement the test here

if __name__ == "__main__":
    unittest.main()

Coba jalankan python -m unittest test.py dan kompilasi masih sukses. Kita belum membuat satu pun unit test, jadi mari kita buat:

class TestFaktorial(unittest.TestCase):
    # We will implement the test here
    def test_non_numeric_input(self):
        self.assertEqual(faktorial("1.5"), "Harap masukkan input numerik (0-9)")

Nah, sekarang kita jalankan python -m unittest test.py dan assertion akan error karena kita belum buat fungsinya.

======================================================================
ERROR: test_non_numeric_input (test.TestFaktorial.test_non_numeric_input)
----------------------------------------------------------------------
NameError: name 'faktorial' is not defined
----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (errors=1)

Kita harus berhenti membuat tes dan mulai membuat kode solusi.

Praktik: Membuat Kode Solusi

Sekarang mari kita buka main.py dan tuliskan kode berikut

def faktorial(user_input: str) -> str:
    if not user_input.isnumeric():
        return "Harap masukkan input numerik (0-9)"

Di sini fungsi faktorial menerima input string dan output string. Kita bisa menggunakan string method bawaan Python isnumeric untuk memastikan input merupakan karakter numerik atau tidak.

Untuk membuat faktorial() bisa diakses kode tes, impor kode solusi ke dalam kode tes. Buka test.py lalu tambahkan kode from main import faktorial pada line pertama

from main import faktorial

import unittest

Jalankan tes lagi: python -m unittest test.py. Seharusnya kali ini sudah berhasil:

.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

Praktik: Membuat Unit Test Kedua

Kita bisa lanjutkan dengan membuat unit test berikutnya. Buka test.py lalu tambahkan kode di bawah test_non_ numeric_input

    def test_non_numeric_input(self):
        self.assertEqual(faktorial("1.5"), "Harap masukkan input numerik (0-9)")

    def test_numeric_input(self):
        self.assertEqual(faktorial("4"), "Nilai faktorialnya adalah 24")

Test ini bertujuan untuk menguji apakah nilai faktorial yang dikembalikan benar. Nilai faktorial 0 adalah 1, kemudian nilai faktorial berikutnya adalah perkalian dari 1x2x... sampai ke bilangan yang dituju.

Coba jalankan python -m unittest test.py, test akan gagal karena fungsi kita belum mengembalikan output hasil faktorial.

AssertionError: None != 'Nilai faktorialnya adalah 24'

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)

Praktik: Membuat Solusi untuk Test Kedua

Kembali buka main.py dan ketikkan kode solusi untuk bilangan faktorial

def faktorial(user_input: str) -> str:
    if not user_input.isnumeric():
        return "Harap masukkan input numerik (0-9)"

    # Cast user_input string to integer
    user_input = int(user_input)

    result = 1
    for i in range(1, user_input+1):
        result *= i

    return "Nilai faktorialnya adalah " + str(result)

Setelah memastikan input numerik, input pasti bisa dikonversi ke bilangan positif. Kita mulai dulu dari 1 karena faktorial dari 0 adalah 1. Selanjutnya kita melakukan perkalian berulang 1x2x3x... pada for loop. Terakhir, kita kembalikan hasilnya sebagai pesan string.

Simpan kode ini dan jalankan lagi python -m unittest test.py. Hasilnya akan kurang lebih seperti ini:

..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

Terlihat bahwa kedua test telah OK.

Praktik: Menyimpan Perubahan pada Git

Kita akan membuat dua commit, yaitu untuk tes dan untuk solusi (implementasi). Untuk membuat commit pada tes lakukan perintah ini pada terminal/CMD:

git add test.py
git commit -m "test: add faktorial unit test"

Pada commit pertama kita hanya menambahkan file-file yang digunakan untuk menulis unit test, yaitu pada praktik ini test.py. Setelah menambahkan file tes, kita menuliskan pesan commit dengan awalan test: untuk menandakan bahwa ini commit untuk test.

Selanjutnya lakukan perintah Git untuk kode solusi:

git add main.py
git commit -m "feat: add faktorial function"

Perhatikan bahwa kini kita menambahkan file untuk solusi, yaitu main.py. Kita tuliskan pesan commit dengan awalan feat: untuk menandakan pembuatan fitur baru.

Demikian panduan penerapan Test Driven Development (TDD) dengan Git. Semoga bermanfaat. Source code untuk praktik di atas terdapat pada link berikut

Rujukan

Beck, K. (2003). Test-driven Development: By Example. Addison-Wesley Professional.

Martin, R. C. (2005, October 6). The Three Rules Of Tdd. http://butunclebob.com.