Traffine I/O

Bahasa Indonesia

2023-02-17

unittest

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.

python
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

  1. Tentukan fungsi dan kelas yang akan diuji.
  2. Buat sebuah kelas yang memperluas kelas TestCase dari unittest.
  3. Buat sebuah metode pengujian. Disarankan agar nama metode pengujian dimulai dengan "test_".
  4. Di dalam metode pengujian, panggil fungsi atau kelas yang akan diuji.
  5. Gunakan pernyataan tegas untuk memeriksa apakah hasil yang diharapkan diperoleh.
  6. 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.

python
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_.

python
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.

python
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().

python
if __name__ == '__main__':
    unittest.main()

Untuk melakukannya dengan cara ini, jalankan perintah berikut.

bash
$ python test_module.py

Melewati atau mengabaikan tes

Untuk melewatkan tes, gunakan unittest.skip(). Anda juga dapat menentukan alasan untuk melewatkan tes.

python
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.

python
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.

python
self.assertEqual(1 + 2, 3)

assertNotEqual(a, b)

Memverifikasi bahwa a dan b tidak sama. Setara dengan a ! = b.

python
self.assertNotEqual(1 + 2, 4)

assertTrue(x)

Memverifikasi bahwa x adalah True.

python
self.assertTrue(1 + 2 == 3)

assertFalse(x)

Memverifikasi bahwa x adalah False

python
self.assertFalse(1 + 2 == 4)

assertIs(a, b)

Memverifikasi bahwa a dan b adalah objek yang sama. Setara dengan a is b.

python
self.assertIs([], [])

assertIsNot(a, b)

Memverifikasi bahwa a dan b bukan objek yang sama. Setara dengan a is not b.

python
self.assertIsNot([], [])

assertIsNone(x)

Memverifikasi bahwa x adalahNone. Setara dengan x is None.

python
self.assertIsNone(None)

assertIsNotNone(x)

Memverifikasi bahwa x bukan None. Setara dengan x is not None.

python
self.assertIsNotNone(1 + 2)

assertIn(a, b)

Memverifikasi bahwa a terkandung di dalam b. Setara dengan a in b.

python
self.assertIn(1, [1, 2, 3])

assertNotIn(a, b)

Memverifikasi bahwa a tidak berada di dalam b. Setara dengan a not in b.

python
self.assertNotIn(4, [1, 2, 3])

assertIsInstance(a, b)

Memverifikasi apakah a adalah contoh dari b.

python
self.assertIsInstance([], list)

assertNotIsInstance(a, b)

Memverifikasi apakah a bukan merupakan contoh dari b.

python
self.assertNotIsInstance([], dict)

assertAlmostEqual(a, b, places=x)

Memverifikasi apakah a dan b sama dalam jumlah digit yang ditentukan.

python
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.

python
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.

python
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.

python
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.

python
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.

python
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.

bash
$ 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.

python
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.

python
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.

python
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.

python
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.

python
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.

python
@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().

python
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().

python
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

https://docs.python.org/2.7/library/unittest.html
https://docs.python.org/3/library/unittest.mock-examples.html

Ryusei Kakujo

researchgatelinkedingithub

Focusing on data science for mobility

Bench Press 100kg!