Di depan Show Setiap hari, ayam saya sedikit malu Pendahuluan Dasar Penggunaan sederhananya adalah: assert expression Mari kita gunakan program untuk menguji ini expression, jika expression setara dengan False, maka raise a AssertionError out> out> out>. Yaitu secara logis setara dengan: if not expression: Lihatlah contoh -contoh ini secara sederhana: >>> assert True Tambahkan parameter anomali ke assert bermaksud TOS dan kalimat Parameter abnormal assert sebenarnya menambahkan informasi string setelah menyatakan ekspresi, yang umumnya digunakan untuk menjelaskan pernyataan. Formatnya adalah sebagai berikut: assert expression <, arguments> Misalnya, silakan lihat kode setelah yang berikut ini Beberapa detail penting Setrika lama dapat mencoba menjalankan segmen kode berikut: >>> assert None, 'None Jika digunakan sebagai ekspresi boolean, itu setara dengan False' Tentu saja, ada aneh numpy >>> a = np.array([1, 2]) Ya, Anda membacanya dengan benar, di mana numpy, di mana pun ada Use a.any() or a.all()...... Akhirnya, coba keduanya lagi: >>> assert np.array([]) Ya, asalkan kosong, berapa banyak dimensi tabung yang setara dengan False Error/Bug¶Semakin komplek fungsi dan program yang dibuat, maka semakin banyak celah yang memungkinkan program terdapat kesalahan. Sebagai contoh, berikut ini adalah error-error yang pernah terjadi di saat menjalankan beberapa kode di module-module sebelumnya: Table of Contents
Di python, setidaknya ada 2 jenis error, yaitu syntax error dan exception.
Kedua jenis error tersebut termasuk yang mudah ditemukan dan diperbaiki, karena biasanya Python bisa menunjukkan lokasi error sebelum atau setelah program gagal dieksekusi. Ada jenis error yang lain yang paling sulit untuk ditemukan, yaitu logic error.
Error pada software juga biasa disebut sebagai bug. Dalam sejarah, bug pada software dapat menyebabkan hal yang sangat fatal, misalnya:
Oleh sebab itu, meskipun kita tidak sedang membuat program seperti contoh di atas, kehati-hatian dalam programming sangat penting. Bahkan walaupun kita yakin program yang kita buat sudah benar, namun pada saat dijalankan banyak situasi tidak ideal yang sebelumnya kita anggap tidak akan terjadi ternyata terjadi. Sebagai contoh kerusakan hardware, user yang mengakses program kita secara bersamaan terlalu banyak, user memasukkan input yang diluar dugaan, dan sebagainya, yang pada akhirnya membuat program kita menjadi error. Selanjutnya mari kita lihat bagaimana langkah-langkah dalam menghindari dan mengatasi bug pada program. Defensive Programming¶Defensive programming adalah sebuah pendekatan dalam memprogram dimana programmer selalu berhati-hati dan memikirkan berbagai kondisi yang memungkinkan terjadinya kesalahan, serta berusaha mengantisipasinya. Mindset defensive programming juga mencari cara paling efektif membangun kode yang memudahkan pencarian dan perbaikan bug jika suatu saat terjadi, terutama bug yang terkait logic error. Berikut adalah beberapa langkah umum dalam defensive programming:
Assertion¶Assertion
adalah suatu pengecekan untuk memastikan suatu kondisi harus benar untuk bisa melakukan proses berikutnya. Mirip seperti if-statement, namun bedanya, jika kondisi Sebagai contoh ada sebuah fungsi untuk menghitung luas sebuah segi empat berdasarkan koordinat dua buah titik, yaitu titik pojok kiri bawah, dan titik pojok kanan atas. Berikut kira-kira fungsi menghitung luas tersebut. def luas_segiempat(x0, y0, x1, y1): """ Menghitung luas segi empat berdasarkan koordinat 2 titik: pojok kiri bawah (x0, y0), dan kanan atas (x1, y1). """ deltax = x1 - x0 deltay = y1 - y0 return deltax * deltay segi4_1 = luas_segiempat(1, 1, 3, 3) segi4_2 = luas_segiempat(2, 4, 3, 3) print(segi4_1 + segi4_2) Terlihat bahwa ketika kode di atas dijalankan, maka akan tertampil nilai 3 yang merupakan penjumlahan luas kedua segi. Sekilas tidak ada yang aneh, namun jika dilihat dengan teliti akan ditemukan logic error. Opsi Solusi Mari kita bahas beberapa opsi yang bisa digunakan untuk menghindari hal tersebut.
x0 = 2 y0 = 4 x1 = 3 y1 = 3 # cek (x0, y0) kiri bawah, dan (x1, y1) kanan atas if x0 < x1 and y0 < y1: # panggil fungsi else: # jangan panggil fungsi, keluarkan info ke user nilai salah Meskipun bisa dilakukan, tetapi tentu hal ini bukanlah solusi terbaik, karena orang kita sendiri atau orang lain mungkin saja lupa untuk menambahkan pengecekan tersebut, dan akhirnya berakibat fatal.
def luas_segiempat(x0, y0, x1, y1): """ Menghitung luas segi empat berdasarkan koordinat 2 titik: pojok kiri bawah (x0, y0), dan kanan atas (x1, y1). """ # cek (x0, y0) kiri bawah, dan (x1, y1) kanan atas if x0 < x1 and y0 < y1: deltax = x1 - x0 deltay = y1 - y0 return deltax * deltay segi4_1 = luas_segiempat(1, 1, 3, 3) segi4_2 = luas_segiempat(2, 4, 3, 3) print(segi4_1 + segi4_2) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-3-931b1318cd94> in <module>() 11 segi4_1 = luas_segiempat(1, 1, 3, 3) 12 segi4_2 = luas_segiempat(2, 4, 3, 3) ---> 13 print(segi4_1 + segi4_2) TypeError: unsupported operand type(s) for +: 'int' and 'NoneType' Ketika
kondisi salah, maka fungsi luas_segiempat tidak mengeksekusi Mengeset Penggunaan Assertion Salah satu solusi yang lebih baik adalah menggunakan assertion. Sebelumnya kita lihat dulu bentuk statement assertion pada python berikut ini: assert <kondisi>, <pesan_error>
Mari kita lihat penggunaannya pada fungsi. def luas_segiempat(x0, y0, x1, y1): """ Menghitung luas segi empat berdasarkan koordinat 2 titik: pojok kiri bawah (x0, y0), dan kanan atas (x1, y1). """ # untuk memastikan koordinat input sudah sesuai asumsi assert x0 < x1 and y0 < y1, "koordinat tidak valid" deltax = x1 - x0 deltay = y1 - y0 return deltax * deltay segi4_1 = luas_segiempat(1, 1, 3, 3) segi4_2 = luas_segiempat(2, 4, 3, 3) print(segi4_1 + segi4_2) --------------------------------------------------------------------------- AssertionError Traceback (most recent call last) <ipython-input-2-1c133d01193d> in <module>() 11 12 segi4_1 = luas_segiempat(1, 1, 3, 3) ---> 13 segi4_2 = luas_segiempat(2, 4, 3, 3) 14 print(segi4_1 + segi4_2) 15 <ipython-input-2-1c133d01193d> in luas_segiempat(x0, y0, x1, y1) 4 5 # untuk memastikan koordinat input sudah sesuai asumsi ----> 6 assert x0 < x1 and y0 < y1, "koordinat tidak valid" 7 8 deltax = x1 - x0 AssertionError: koordinat tidak valid Terlihat bahwa program akan memunculkan Assertion Error beserta pesannya. Dengan demikian maka siapapun yang menggunakan fungsi tersebut akan segera menyadari adanya kesalahan dan tau secara persis di mana letak kesalahan tersebut. Sekali lagi perlu diperhatikan, Assertion akan membuat program berhenti, untuk itu pastikan hanya menggunakan assertion di saat tidak ada opsi lain yang lebih baik tanpa harus membuat program berhenti. Exception Handling¶Sebelumnya kita telah membahas tentang perbedaan syntax error dengan exception, dimana exception muncul saat program sedang dieksekusi. Ada banyak jenis exception bawaan Python (built-in exception), di antaranya:
Untuk lengkapnya bisa dilihat pada: https://docs.python.org/3/library/exceptions.html Dalam membuat program, selain correctness (seperti yang ditekankan pada penggunaan assertion) kita juga perlu memperhatikan aspek robustness atau ketangguhan. Program yang robust artinya tidak mudah crash atau terhenti walau terjadi error. Sekilas kedua prinsip tersebut terasa bertentangan, namun sebenarnya, masing-masing dapat diterapkan pada kondisi yang tepat. Sebagai contoh, anggaplah kita membuat program yang meminta inputan user berupa 4 buah integer sebagai representasi 2 koordinat titik pojok (kiri bawah dan kanan atas) pada segi empat, yaitu x0, y0, x1, y1. x0 = int(input("Koordinat x0:")) y0 = int(input("Koordinat y0:")) x1 = int(input("Koordinat x1:")) y1 = int(input("Koordinat y1:")) luas = luas_segiempat(x0, y0, x1, y1) print("Luas segi empat adalah:", luas) --------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-4-54c43d00cd70> in <module>() ----> 1 x0 = int(input("Koordinat x0:")) 2 y0 = int(input("Koordinat y0:")) 3 x1 = int(input("Koordinat x1:")) 4 y1 = int(input("Koordinat y1:")) 5 ValueError: invalid literal for int() with base 10: '' Ternyata, saat dijalankan user yang niat awalnya memasukkan nilai Penanganan exception, agar program tidak terhenti biasa disebut dengan exception handling. Penggunaan Exception Handling try: # kode yang mungkin menimbulkan exception except: # apa yang dilakukan jika terjadi exception else: # dijalankan jika kode pada try tidak menimbulkan exception
Berikut
ini contoh penggunaan try: x0 = int(input("Koordinat x0:")) y0 = int(input("Koordinat y0:")) x1 = int(input("Koordinat x1:")) y1 = int(input("Koordinat y1:")) except: print("Koordinat harus integer") luas = luas_segiempat(x0, y0, x1, y1) print("Luas segi empat adalah:", luas) Koordinat x0:1 Koordinat y0:1 Koordinat x1:5 Koordinat y1:t Koordinat harus integer --------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-5-b39738a0c8ef> in <module>() 7 print("Koordinat harus integer") 8 ----> 9 luas = luas_segiempat(x0, y0, x1, y1) 10 print("Luas segi empat adalah:", luas) NameError: name 'y1' is not defined Terlihat bahwa jika diinputkan seperti sebelumnya, yaitu Error yang terjadi sekarang yaitu dikarenakan
saat memanggil fungsi try: x0 = int(input("Koordinat x0:")) y0 = int(input("Koordinat y0:")) x1 = int(input("Koordinat x1:")) y1 = int(input("Koordinat y1:")) except: print("Koordinat harus integer") else: # hanya dieksekusi jika tidak ada exception luas = luas_segiempat(x0, y0, x1, y1) print("Luas segi empat adalah:", luas) Koordinat x0:1 Koordinat y0:1 Koordinat x1:5 Koordinat y1:t Koordinat harus integer Program di atas jika diberikan input yang tidak valid maka tidak akan mengeluarkan error. Sebagai tambahan, bagaimana jika kita ingin memberikan kesempatan kepada user untuk mengulangi input maksimal sebanyak 3 kali? Anda bisa menggunakan contoh kode di bawah ini. count = 0 while count < 3: # memastikan bahwa akan ada 4 nilai integer yang valid try: x0 = int(input("Koordinat x0:")) y0 = int(input("Koordinat y0:")) x1 = int(input("Koordinat x1:")) y1 = int(input("Koordinat y1:")) except ValueError: count += 1 print("Koordinat harus integer. Sisa percobaan:", 3 - count) else: luas = luas_segiempat(x0, y0, x1, y1) print("Luas segi empat adalah:", luas) Koordinat x0: Koordinat harus integer. Sisa percobaan: 2 Koordinat x0: Koordinat harus integer. Sisa percobaan: 1 Koordinat x0: Koordinat harus integer. Sisa percobaan: 0 Testing¶Ketika anda selesai membuat sebuah fungsi atau program, dan sudah melakukan prinsip-prinsip defensive programming di atas, maka langkah selanjutnya adalah menguji kebenaran fungsi atau program tersebut dengan berbagai kemungkinan input. Pada umumnya, pengujian dilakukan dengan tahapan berikut:
Ada 2 pendekatan dalam melakukan testing:
Black box testing¶Mari kita lihat contoh spesifikasi fungsi yang akan dilakukan pengetesan. def konversi_nilai(nilai): """menerima input berupa float 0 <= nilai <= 100 (antara 0 sampai 100) return "A" jika nilai > 80, "B" jika 50 < nilai <= 80, "E" selainnya. """ pass Sebelum menguji, maka kita perlu membuat test-case berdasarkan spesifikasi fungsi di atas. Beberapa panduan dalam menyusun test-cases menggunakan black-box testing adalah:
Berdasarkan panduan tersebut, maka dari spesifikasi fungsi di atas, kita dapat menemukan partisi input yang memberikan hasil berbeda, yaitu 50 dan 80. Sementara kita juga perlu mengecek nilai ekstrim, yaitu 0 dan 100, serta nilai yang tidak valid.
Berikut contoh test-cases yang bisa digunakan untuk menguji fungsi
Menjalankan testing¶Berikut ini adalah implementasi fungsi def konversi_nilai(nilai): """menerima input berupa float 0 <= nilai <= 100 (antara 0 sampai 100) return "A" jika nilai > 80, "B" jika 50 < nilai <= 80, "E" selainnya. """ if nilai >= 80: return "A" elif nilai >= 50: return "B" else: return "E" Setelah menyusun test-case, langkah selanjutnya adalah menjalankan proses testing. Ada berbagai cara untuk melakukan ini, namun kita bisa mulai dengan yang paling sederhana, yaitu dengan print perbandingan output fungsi dengan output pada test-case seperti di bawah ini. print("Test case 1:", konversi_nilai(80) == "B") print("Test case 2:", konversi_nilai(80.01) == "A") print("Test case 3:", konversi_nilai(50) == "E") print("Test case 4:", konversi_nilai(50.01) == "B") print("Test case 5:", konversi_nilai(100) == "A") print("Test case 6:", konversi_nilai(0) == "E") try: r = konversi_nilai(100.01) print("Test case 7: False") except: print("Test case 7: True") try: r = konversi_nilai(-1) print("Test case 8: False") except: print("Test case 8: True") Test case 1: False Test case 2: True Test case 3: False Test case 4: True Test case 5: True Test case 6: True Test case 7: False Test case 8: False Ternyata dari 8 test case yang kita ajukan, ada 4 yang gagal. Coba anda temukan letak kesalahannya, dan perbaiki agar bisa lulus di semua test case tersebut. Berikut versi fungsi def konversi_nilai(nilai): """menerima input berupa float 0 <= nilai <= 100 (antara 0 sampai 100) return "A" jika nilai > 80, "B" jika 50 < nilai <= 80, "E" selainnya. """ assert 0 <= nilai and nilai <= 100, "nilai harus antara 0 sampai 100" if nilai > 80: return "A" elif nilai > 50: return "B" else: return "E" print("Test case 1:", konversi_nilai(80) == "B") print("Test case 2:", konversi_nilai(80.01) == "A") print("Test case 3:", konversi_nilai(50) == "E") print("Test case 4:", konversi_nilai(50.01) == "B") print("Test case 5:", konversi_nilai(100) == "A") print("Test case 6:", konversi_nilai(0) == "E") try: r = konversi_nilai(100.01) print("Test case 7: False") except: print("Test case 7: True") try: r = konversi_nilai(-1) print("Test case 8: False") except: print("Test case 8: True") Test case 1: True Test case 2: True Test case 3: True Test case 4: True Test case 5: True Test case 6: True Test case 7: True Test case 8: True Cara lainnya kita bisa menggunakan assertion dan fungsi, serta membuat file khusus yang berisi semua testing. Misalnya kita membuat file baru bernama my_test.py yang isinya adalah sebagai berikut: def test_konversi_nilai(): print("Test case 1:", konversi_nilai(80) == "B") print("Test case 2:", konversi_nilai(80.01) == "A") print("Test case 3:", konversi_nilai(50) == "E") print("Test case 4:", konversi_nilai(50.01) == "B") print("Test case 5:", konversi_nilai(100) == "A") print("Test case 6:", konversi_nilai(0) == "E") try: r = konversi_nilai(100.01) print("Test case 7: False") except: print("Test case 7: True") try: r = konversi_nilai(-1) print("Test case 8: False") except: print("Test case 8: True") print('Pengujian fungsi konversi_nilai') test_konversi_nilai() print('Pengujian selesai') Pengujian fungsi konversi_nilai Test case 1: True Test case 2: True Test case 3: True Test case 4: True Test case 5: True Test case 6: True Test case 7: True Test case 8: True Pengujian selesai Glass box testing¶Pembuatan test-case pada glass box testing dilakukan berdasarkan kode program. Tujuannya adalah memastikan bahwa setiap jalur yang ada pada kode pernah dieksekusi minimal satu kali. Beberapa panduan antara lain:
def konversi_nilai(nilai): """menerima input berupa float 0 <= nilai <= 100 (antara 0 sampai 100) return "A" jika nilai > 80, "B" jika 50 < nilai <= 80, "E" selainnya. """ if nilai >= 80: return "A" elif nilai >= 50: return "B" else: return "E" Berdasarkan fungsi konversi_nilai asli di atas, maka beberapa test-case yang bisa dibuat adalah:
Kita sudah melihat bahwa, jika test-case tersebut diberikan pada fungsi Debugging¶Testing vs Debugging Testing dan debugging sama-sama terkait dengan usaha agar kode kita tidak memiliki bug, namun keduanya adalah proses yang berbeda. Berikut perbedaannya:
Cara-cara dalam melakukan debugging:
Debugging dengan Print¶Pertama-tama, mari kita lihat contoh program di bawah ini. Fungsi # sum_genap_ganjil_v1.py def sum_genap_ganjil(n): assert isinstance(n, int) and n >= 0, "n harus berupa non-negatif integer" sum1 = 0 sum2 = 0 for i in range(1, n): if i % 2 == 1: #ganjil suml = sum1 + i else: #genap sum2 = sum2 + i return sum1, sum2 Pertama-tama, mari kita buat beberapa test-case untuk menguji fungsi tersebut.
# testing_sum_genap_ganjil.py print(sum_genap_ganjil(0) == (0, 0)) # gunakan tuple () jika terdapat lebih dari 1 nilai pada return print(sum_genap_ganjil(1) == (1, 0)) print(sum_genap_ganjil(2) == (1, 2)) print(sum_genap_ganjil(5) == (9, 6)) print(sum_genap_ganjil(6) == (9, 12)) True False False False False Terlihat bahwa masih terdapat bug pada fungsi tersebut sehingga dari 5 test-case hanya 1 yang benar. Mari kita coba debug menggunakan fungsi print(sum_genap_ganjil(5)) Saat # sum_genap_ganjil_v2.py def sum_genap_ganjil(n): assert isinstance(n, int) and n >= 0, "n harus berupa non-negatif integer" sum1 = 0 sum2 = 0 for i in range(1, n): print('i', i) if i % 2 == 1: #ganjil suml = sum1 + i print('sum ganjil:', sum1) else: #genap sum2 = sum2 + i print('sum genap:', sum2) return sum1, sum2 print(sum_genap_ganjil(5)) i 1 sum ganjil: 0 i 2 sum genap: 2 i 3 sum ganjil: 0 i 4 sum genap: 6 (0, 6) Dari output di atas, kita bisa melihat beberapa kesalahan.
Berikut adalah fungsi yang telah diperbaiki: # sum_genap_ganjil.py def sum_genap_ganjil(n): assert isinstance(n, int) and n >= 0, "n harus berupa non-negatif integer" sum1 = 0 sum2 = 0 for i in range(1, n+1): if i % 2 == 1: #ganjil sum1 = sum1 + i else: #genap sum2 = sum2 + i return sum1, sum2 Mari kita lakukan testing kembali. print(sum_genap_ganjil(0) == (0, 0)) # gunakan tuple () jika terdapat lebih dari 1 nilai pada return print(sum_genap_ganjil(1) == (1, 0)) print(sum_genap_ganjil(2) == (1, 2)) print(sum_genap_ganjil(5) == (9, 6)) print(sum_genap_ganjil(6) == (9, 12)) Terkadang error terjadi karena hal yang sepele, misalnya karena typo. Namun jika kita tidak menggunakan cara yang tepat dalam mendebug, misalnya hanya dengan membaca kembali kode, mungkin kita akan kesulitan menemukan kesalahannya. Debugger pada IDLE¶Fitur standard sebuah debugger:
Mengaktifkan Debugger
Menu Debug Control IDLE
Menjalankan Debug Program
Terlihat bahwa ada yang aneh saat program eksekusi baris Selamat anda telah menyelesaikan Modul 7!! Mohon berkenan memberikan Rating dan Feedback agar kami dapat meningkatkan kualitas modul ini! |