Apa itu unittest
Unittest Python adalah kerangka kerja pengujian yang disertakan dalam pustaka standar Python. unittest memungkinkan Anda untuk menulis tes unit untuk kode Python Anda.
unittest menyediakan fitur-fitur berikut
- Pembuatan kelas pengujian
- Pembuatan metode pengujian
- Eksekusi tes secara otomatis
- Menggunakan pernyataan
- Melewati atau mengabaikan tes
Berikut ini adalah contoh penulisan tes menggunakan unittest.
import unittest
class MyTest(unittest.TestCase):
def test_addition(self):
self.assertEqual(1 + 1, 2)
def test_subtraction(self):
self.assertEqual(3 - 1, 2)
if __name__ == '__main__':
unittest.main()
Pada contoh ini, kita mendefinisikan kelas tes bernama MyTest dan dua metode tes bernama test_addition
dan test_subtraction
. Masing-masing menyatakan bahwa 1 + 1 sama dengan 2 dan 3 - 1 sama dengan 2.
Terakhir, unittest.main()
dipanggil untuk mengeksekusi tes secara otomatis.
Menggunakan unittest
meningkatkan kualitas kode dan membuatnya lebih mudah untuk menemukan bug. Hal ini juga meningkatkan proses pengembangan secara keseluruhan dengan memberi tahu pengembang ketika mereka perlu memperbaiki kode mereka dan bahwa pengujian telah gagal.
Terminologi unittest
Unittest Python memiliki beberapa istilah berikut ini.
Term | Deskripsi |
---|---|
Test case | Unit pengujian yang dijalankan oleh unittest. Biasanya berhubungan dengan satu fungsi pengujian. |
Test suite | Pengelompokan beberapa kasus uji. Dibuat menggunakan objek unittest.TestSuite . |
Test runner | Alat bantu untuk menjalankan rangkaian tes. Terdapat beberapa alat bantu, seperti unittest.TextTestRunner dan unittest.XMLTestRunner . |
Test fixture | Kode yang melakukan persiapan dan pasca-pemrosesan yang diperlukan untuk menjalankan kasus uji. Didefinisikan oleh metode setUp() dan tearDown() . |
Assertion | Kode untuk menentukan hasil tes. Ada assertEqual() , assertTrue() , dan seterusnya. |
Test runner output | Information output by the test runner. It includes test results, execution time, etc. |
Skip | Keluaran informasi oleh pelari tes. Ini termasuk hasil tes, waktu eksekusi, dll. |
Assertion error | Pengecualian dimunculkan ketika pernyataan gagal. |
Test run error | Kesalahan yang terjadi selama eksekusi rangkaian pengujian. Biasanya mencakup kesalahan fungsi pengujian, dll. |
Test run failure | Kesalahan yang terjadi ketika sebuah pernyataan gagal selama eksekusi rangkaian tes. |
prosedur unittest
- Tentukan fungsi dan kelas yang akan diuji.
- Buat sebuah kelas yang memperluas kelas
TestCase
dari unittest. - Buat sebuah metode pengujian. Disarankan agar nama metode pengujian dimulai dengan "test_".
- Di dalam metode pengujian, panggil fungsi atau kelas yang akan diuji.
- Gunakan pernyataan tegas untuk memeriksa apakah hasil yang diharapkan diperoleh.
- Jalankan kelas uji dengan
unittest.main()
.
Contoh konkret ditunjukkan di bawah ini. Di sini, kita mendefinisikan fungsi reverse_string
untuk membalikkan sebuah string sebagai fungsi yang akan diuji, dan membuat kelas uji untuk menguji fungsi tersebut.
def reverse_string(s):
return s[::-1]
import unittest
class TestReverseString(unittest.TestCase):
def test_reverse_string(self):
self.assertEqual(reverse_string('hello'), 'olleh')
self.assertEqual(reverse_string('world'), 'dlrow')
if __name__ == '__main__':
unittest.main()
Kode di atas mendefinisikan kelas TestReverseString sebagai kelas uji dan membuat metode test_reverse_string sebagai metode uji di dalamnya. test_reverse_string menggunakan fungsi reverse_string dan mengecek apakah nilai yang dikembalikan sudah benar dengan menggunakan metode assertEqual.
Terakhir, pada bagian if name == 'main':
, kita memanggil unittest.main()
untuk menjalankan pengujian jika file ini dieksekusi secara langsung.
Penggunaan rinci dari unittest
Bagian ini menjelaskan detail penggunaan unittest.
Membuat kelas uji coba
Ketika menggunakan unittest, Anda perlu membuat kelas uji untuk mendefinisikan kasus uji. Kelas uji harus mewarisi dari kelas unittest.TestCase
. Jika Anda mendefinisikan metode pengujian, nama metode harus dimulai dengan test_
.
import unittest
class MyTest(unittest.TestCase):
def test_addition(self):
self.assertEqual(1 + 1, 2)
def test_subtraction(self):
self.assertEqual(3 - 1, 2)
Gunakan Assertions
unittest menggunakan assertions untuk menentukan keberhasilan atau kegagalan suatu pengujian. Asersi digunakan untuk memverifikasi bahwa pengujian berjalan seperti yang diharapkan.
Sebagai contoh, pernyataan berikut ini dapat digunakan untuk memverifikasi bahwa nilainya sama.
import unittest
class MyTest(unittest.TestCase):
def test_addition(self):
self.assertEqual(1 + 1, 2)
def test_subtraction(self):
self.assertEqual(3 - 1, 2)
Menjalankan tes secara otomatis
Ketika menggunakan unittest, tes dapat dijalankan secara otomatis. Cara termudah adalah dengan memanggil unittest.main()
.
if __name__ == '__main__':
unittest.main()
Untuk melakukannya dengan cara ini, jalankan perintah berikut.
$ python test_module.py
Melewati atau mengabaikan tes
Untuk melewatkan tes, gunakan unittest.skip()
. Anda juga dapat menentukan alasan untuk melewatkan tes.
import unittest
class MyTest(unittest.TestCase):
@unittest.skip("reason for skipping here")
def test_addition(self):
self.assertEqual(1 + 1, 2)
Metode pernyataan dari unittest
Pernyataan assert digunakan untuk memverifikasi bahwa fungsi yang diuji mengembalikan hasil yang diharapkan. Sebagai contoh, Anda dapat mendefinisikan kasus uji sebagai berikut.
import unittest
def add(a, b):
return a + b
class MyTest(unittest.TestCase):
def test_add(self):
self.assertEqual(add(2, 3), 5)
self.assertNotEqual(add(2, 3), 6)
self.assertTrue(add(2, 3) > 4)
self.assertFalse(add(2, 3) < 4)
Pada contoh di atas, fungsi add()
didefinisikan sebagai fungsi yang akan diuji. Kasus uji memverifikasi bahwa fungsi add()
mengembalikan hasil yang diharapkan. Sebagai contoh, self.assertEqual(add(2, 3), 5)
memverifikasi bahwa hasil dari add(2, 3)
adalah 5. Jika semua pernyataan asersi berhasil, maka kasus uji lolos; jika ada pernyataan asersi yang gagal, maka kasus uji gagal.
Di bawah ini adalah metode-metode pernyataan utama.
assertEqual(a, b)
Memverifikasi bahwa a dan b sama. Setara dengan a == b
.
self.assertEqual(1 + 2, 3)
assertNotEqual(a, b)
Memverifikasi bahwa a dan b tidak sama. Setara dengan a ! = b
.
self.assertNotEqual(1 + 2, 4)
assertTrue(x)
Memverifikasi bahwa x adalah True
.
self.assertTrue(1 + 2 == 3)
assertFalse(x)
Memverifikasi bahwa x adalah False
self.assertFalse(1 + 2 == 4)
assertIs(a, b)
Memverifikasi bahwa a dan b adalah objek yang sama. Setara dengan a is b
.
self.assertIs([], [])
assertIsNot(a, b)
Memverifikasi bahwa a dan b bukan objek yang sama. Setara dengan a is not b
.
self.assertIsNot([], [])
assertIsNone(x)
Memverifikasi bahwa x adalahNone
. Setara dengan x is None
.
self.assertIsNone(None)
assertIsNotNone(x)
Memverifikasi bahwa x bukan None
. Setara dengan x is not None
.
self.assertIsNotNone(1 + 2)
assertIn(a, b)
Memverifikasi bahwa a terkandung di dalam b. Setara dengan a in b
.
self.assertIn(1, [1, 2, 3])
assertNotIn(a, b)
Memverifikasi bahwa a tidak berada di dalam b. Setara dengan a not in b
.
self.assertNotIn(4, [1, 2, 3])
assertIsInstance(a, b)
Memverifikasi apakah a adalah contoh dari b.
self.assertIsInstance([], list)
assertNotIsInstance(a, b)
Memverifikasi apakah a bukan merupakan contoh dari b.
self.assertNotIsInstance([], dict)
assertAlmostEqual(a, b, places=x)
Memverifikasi apakah a dan b sama dalam jumlah digit yang ditentukan.
self.assertAlmostEqual(1/3, 0.3333333333333333, places=5)
assertNotAlmostEqual(a, b, places=x)
Memverifikasi apakah a dan b tidak sama dalam jumlah digit yang ditentukan.
self.assertNotAlmostEqual(1/3, 0.333333333, places=7)
assertRaises(exc, func, *args, **kwargs)
Menjalankan pengujian dengan harapan bahwa pengecualian yang ditentukan akan dimunculkan. Artinya, metode ini digunakan untuk memverifikasi bahwa fungsi yang sedang diuji memunculkan pengecualian.
Metode assertRaises
membutuhkan dua argumen. Argumen pertama menentukan jenis pengecualian yang diharapkan, dan argumen kedua adalah fungsi yang akan diuji. Berikut ini adalah contoh penggunaan metode assertRaises.
import unittest
def divide(a, b):
if b == 0:
raise ZeroDivisionError('division by zero')
return a / b
class MyTest(unittest.TestCase):
def test_divide(self):
self.assertRaises(ZeroDivisionError, divide, 1, 0)
Pada contoh di atas, fungsi divide()
didefinisikan untuk memunculkan pengecualian ZeroDivisionError
jika terjadi pembagian nol. Metode test_divide
dari kelas MyTest
menggunakan metode assertRaises
untuk memastikan bahwa fungsi divide()
memunculkan pengecualian ZeroDivisionError
. Argumen pertama dari metode assertRaises
adalah ZeroDivisionError
, dan argumen kedua adalah fungsi divide()
dan argumennya. Dengan kata lain, kita berharap untuk menjalankan divide(1, 0)
dan mendapatkan ZeroDivisionError
.
Metode assertRaises
akan gagal dalam pengujian jika pengecualian yang ditentukan tidak dimunculkan. Metode ini juga mengembalikan objek pengecualian jika pengecualian dimunculkan. Objek pengecualian juga dapat digunakan untuk memverifikasi bahwa pengecualian tersebut merupakan tipe yang benar. Sebagai contoh, Anda dapat menggunakan metode assertRaises
sebagai berikut.
import unittest
def divide(a, b):
if b == 0:
raise ZeroDivisionError('division by zero')
return a / b
class MyTest(unittest.TestCase):
def test_divide(self):
with self.assertRaises(ZeroDivisionError) as cm:
divide(1, 0)
self.assertEqual(str(cm.exception), 'division by zero')
Pada contoh di atas, metode assertRaises
digunakan dengan pernyataan with
. Dengan menggunakan pernyataan with
, kita mendapatkan objek pengecualian, yang merupakan nilai balik dari metode assertRaises
, dan memverifikasi bahwa pengecualian tersebut memiliki tipe yang benar. cm.exception
merepresentasikan objek pengecualian itu sendiri. str(cm.exception)
mengembalikan sebuah string yang merepresentasikan pesan kesalahan dari objek pengecualian. Metode self.assertEqual
digunakan untuk memverifikasi bahwa pesan kesalahan dalam cm.exception
adalah pesan yang diharapkan.
Metode assertRaises
hanya dapat memeriksa satu pengecualian. Jika Anda ingin memeriksa beberapa pengecualian, Anda harus memanggil metode assertRaises
beberapa kali. Selain itu, jika tidak ada argumen yang dilewatkan, AssertionError
akan dimunculkan.
Sebagai contoh, Anda dapat menggunakan metode assertRaises
sebagai berikut.
import unittest
def divide(a, b):
if b == 0:
raise ZeroDivisionError('division by zero')
elif a < 0:
raise ValueError('a must be non-negative')
return a / b
class MyTest(unittest.TestCase):
def test_divide(self):
self.assertRaises(ZeroDivisionError, divide, 1, 0)
self.assertRaises(ValueError, divide, -1, 2)
Pada contoh di atas, fungsi divide()
didefinisikan untuk memunculkan pembagian dengan nol atau pengecualian ValueError
. Metode test_divide
dari kelas MyTest
menggunakan metode assertRaises
untuk memastikan bahwa fungsi divide()
memunculkan pengecualian yang ditentukan. Beberapa pemanggilan ke metode assertRaises
akan memeriksa beberapa pengecualian.
Perhatikan bahwa metode assertRaises
juga dapat ditulis menggunakan context manager sebagai berikut.
import unittest
def divide(a, b):
if b == 0:
raise ZeroDivisionError('division by zero')
elif a < 0:
raise ValueError('a must be non-negative')
return a / b
class MyTest(unittest.TestCase):
def test_divide(self):
with self.assertRaises(ZeroDivisionError):
divide(1, 0)
with self.assertRaises(ValueError):
divide(-1, 2)
Dalam kasus ini, tidak perlu menentukan pengecualian dalam argumen pertama metode assertRaises
. Selain itu, dengan menggunakan context manager, hanya pengecualian yang dimunculkan di dalam blok with
yang akan ditangkap.
unittest test runner
unittest menyediakan sebuah pelari tes untuk melaporkan hasil tes. Test runner menyediakan antarmuka untuk mengelola uji coba dan melaporkan hasilnya. Di bawah ini adalah test runner utama yang tersedia di unittest.
unittest.main()
Ini adalah test runner default yang disediakan oleh unittest. Dengan runner ini, Anda dapat menjalankan pengujian dari baris perintah. Tes dapat dijalankan dengan mengeksekusi file tes secara langsung, seperti yang ditunjukkan di bawah ini.
$ python test_module.py
unittest.TextTestRunner()
Test runner ini digunakan untuk melaporkan hasil pengujian dalam format teks. Hasil pengujian dapat ditampilkan di konsol sebagai berikut.
import unittest
if __name__ == '__main__':
suite = unittest.TestLoader().discover('.')
unittest.TextTestRunner().run(suite)
unittest.HTMLTestRunner()
Test runner ini dirancang untuk melaporkan hasil pengujian dalam format HTML. Anda dapat membuat laporan dalam format HTML sebagai berikut.
import unittest
import HTMLTestRunner
if __name__ == '__main__':
suite = unittest.TestLoader().discover('.')
with open('test_report.html', 'wb') as f:
HTMLTestRunner.HTMLTestRunner(stream=f).run(suite)
Metode khusus unittest
unittest memiliki metode khusus untuk menyiapkan dan membersihkan pengujian. Dengan menggunakan metode-metode tersebut, Anda dapat menulis kode pengujian dengan lebih efektif. Metode-metode khusus utama tercantum di bawah ini.
setUp()
Metode setUp()
mendefinisikan proses yang akan dieksekusi sebelum kasus uji dieksekusi. Sebagai contoh, Anda dapat mendefinisikan proses untuk menginisialisasi objek yang biasa digunakan dalam kasus uji, atau untuk membuat koneksi database. Metode setUp()
dieksekusi hanya sekali per kasus uji.
import unittest
class MyTest(unittest.TestCase):
def setUp(self):
self.my_object = MyObject()
def test_something(self):
result = self.my_object.do_something()
self.assertEqual(result, expected_result)
Pada contoh di atas, metode setUp()
menginisialisasi objek MyObject
agar dapat digunakan dalam kasus uji.
tearDown()
Metode tearDown()
mendefinisikan pemrosesan yang akan dilakukan setelah kasus uji dieksekusi. Sebagai contoh, Anda dapat mendefinisikan proses seperti memutuskan koneksi database. Metode tearDown()
dieksekusi hanya sekali per kasus uji.
import unittest
class MyTest(unittest.TestCase):
def setUp(self):
self.my_object = MyObject()
def tearDown(self):
self.my_object.close()
def test_something(self):
result = self.my_object.do_something()
self.assertEqual(result, expected_result)
Pada contoh di atas, metode tearDown()
memutuskan objek MyObject
.
Pewarisan metode setUp() dan tearDown()
Metode setUp()
dan tearDown()
juga dapat menggunakan pewarisan untuk mendefinisikan pemrosesan pra- dan pasca-pemrosesan yang sama untuk beberapa kasus pengujian. Sebagai contoh, untuk melakukan pemrosesan inisialisasi yang umum untuk beberapa kasus uji, buat kelas induk yang umum dan tentukan metode setUp()
di kelas induk.
import unittest
class MyObjectTestCase(unittest.TestCase):
def setUp(self):
self.my_object = MyObject()
def tearDown(self):
self.my_object.close()
class TestSomething(MyObjectTestCase):
def test_something(self):
result = self.my_object.do_something()
self.assertEqual(result, expected_result)
class TestSomethingElse(MyObjectTestCase):
def test_something_else(self):
result = self.my_object.do_something_else()
self.assertEqual(result, expected_result)
Pada contoh di atas, kelas MyObjectTestCase
didefinisikan sebagai kelas induk untuk proses inisialisasi umum. Kelas TestSomething
dan TestSomethingElse
masing-masing diwarisi dari kelas MyObjectTestCase
, dan metode setUp()
dan tearDown()
untuk menggunakan objek MyObject
diwarisi secara otomatis.
Dengan demikian, unittest memungkinkan definisi yang fleksibel dari pra dan pasca-pemrosesan kasus uji menggunakan metode setUp()
dan tearDown()
. Selain itu, dengan menggunakan kelas dan pewarisan, Anda dapat dengan mudah mengimplementasikan prapemrosesan dan pascapemrosesan umum untuk beberapa kasus uji.
setUpClass() dan tearDownClass()
setUpClass()
adalah metode yang dipanggil sebelum kelas uji dieksekusi. Metode ini digunakan untuk mengatur resource yang digunakan oleh kelas uji.
tearDownClass()
adalah metode yang dipanggil setelah kelas uji dieksekusi. Metode ini dieksekusi setelah semua pengujian selesai dan digunakan untuk membersihkan resource yang digunakan oleh kelas uji.
Metode setUpClass()
dan tearDownClass()
didefinisikan sebagai berikut.
@classmethod
def setUpClass(cls):
pass
@classmethod
def tearDownClass(cls):
pass
Metode setUpClass()
dan tearDownClass()
didefinisikan sebagai metode kelas. Dengan demikian, metode-metode ini dieksekusi di tingkat kelas dan dapat menggunakan variabel kelas dan metode kelas.
Metode setUpClass()
dapat digunakan, misalnya, untuk membuat koneksi database, membuat file untuk pengujian, atau mengatur resource lainnya.
Metode tearDownClass()
dapat digunakan, misalnya, untuk menutup koneksi database, menghapus file untuk pengujian, atau melepaskan resource lainnya.
Berikut ini adalah contoh penggunaan metode setUpClass()
dan tearDownClass()
.
import unittest
import os
class MyTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.test_dir = 'test'
os.makedirs(cls.test_dir)
def test_example(self):
test_file = os.path.join(self.test_dir, 'test.txt')
with open(test_file, 'w') as f:
f.write('test')
@classmethod
def tearDownClass(cls):
os.rmdir(cls.test_dir)
Pada contoh di atas, metode setUpClass()
membuat direktori bernama test
. Metode test_example()
membuat sebuah file bernama test.txt dalam direktori test
. Metode tearDownClass()
menghapus direktori test
. Dengan demikian, dengan mengatur resource yang digunakan oleh tes dengan metode setUpClass()
, Anda dapat menghindari pengaruh silang antar tes.
subTest
subTest ()
adalah fungsi yang digunakan oleh unittest Python untuk berulang kali menjalankan pengujian yang sama menggunakan beberapa nilai input. Biasanya, fungsi ini digunakan untuk menguji satu fungsi pengujian dengan menggunakan beberapa nilai masukan yang berbeda.
subTest()
dapat digunakan untuk mengidentifikasi nilai input yang gagal jika kasus uji gagal. Selain itu, subTest()
dapat digunakan untuk melanjutkan eksekusi kasus uji berikutnya meskipun fungsi uji gagal.
Berikut ini adalah contoh penggunaan subTest()
.
import unittest
class TestMath(unittest.TestCase):
def test_add(self):
test_cases = [(2, 3, 5), (-2, 3, 1), (0, 0, 0)]
for a, b, expected in test_cases:
with self.subTest(a=a, b=b):
result = a + b
self.assertEqual(result, expected)
In this example, the test_add()
function runs the same test with several different input values. By using subTest()
, the test results for each input value can be displayed independently.
subTest()
is used with with
statements. By making assertions within the with
block, the test cases are executed independently for each input value. The argument to subTest()
can also be an input value passed as a keyword argument.
Catatan tentang penulisan tes menggunakan unittest
Berikut ini adalah hal-hal yang perlu diperhatikan saat menulis tes menggunakan unittest.
- Siapkan data tes dengan benar
Saat menulis tes, data tes yang sesuai harus disiapkan. Data yang tidak mencukupi atau menggunakan data yang salah dapat mengakibatkan pengujian yang tidak memadai. Hal ini juga dapat membuat pengujian menjadi lebih rumit. - Hindari ketergantungan pengujian
Anda harus menghindari penulisan tes yang bergantung pada urutan pelaksanaan tes. Tes ini rentan dan dapat gagal jika urutan pelaksanaan tes berubah. - Perincian pengujian
Perincian tes sangat penting. Menulis tes kecil akan memudahkan untuk mengidentifikasi penyebab masalah ketika terjadi. Anda juga dapat menggabungkan tes-tes kecil untuk membuat tes yang lebih besar. - Kejelasan pesan kesalahan
Ketika sebuah tes gagal, mungkin diperlukan waktu lebih lama untuk mengidentifikasi masalah jika pesan kesalahan sulit dipahami. Upaya harus dilakukan untuk membuat pesan kesalahan menjadi jelas dan mudah dimengerti. - Urutan eksekusi pengujian
Karena unittest tidak menjamin urutan eksekusi pengujian, state dapat dibagi di antara pengujian. Oleh karena itu, setiap metode pengujian harus dieksekusi secara independen tanpa terpengaruh oleh metode pengujian sebelumnya.
Referensi