Pengujian Otomatis dengan Pytest

Terjemahan artikel disiapkan khusus untuk siswa kursus Python QA Engineer .




Kita hidup di era ketika perangkat lunak bergerak sangat cepat ke pasar. Karena itu, proses pengembangan menjadi sangat menegangkan. Tingkat implementasi perangkat lunak yang tinggi dan pengiriman yang cepat terlihat seperti bagian yang baik dari model bisnis, tetapi muncul pertanyaan di sini tentang bagaimana memberikan perangkat lunak dengan kualitas yang tepat.

Mengapa kita perlu tes otomatis


Ada banyak keuntungan untuk pengujian otomatis, berikut adalah tiga yang utama:
Penggunaan Kembali: Tidak perlu menulis skrip baru setiap kali, bahkan ketika versi baru dari sistem operasi dirilis, kecuali ada kebutuhan mendesak untuk itu.
Keandalan: Orang cenderung membuat kesalahan, dan mobil membuatnya lebih kecil kemungkinannya. Dan mereka bekerja lebih cepat ketika melakukan langkah / tes berulang yang perlu dilakukan terus menerus.
Bekerja 24/7: Anda dapat memulai pengujian kapan saja, bahkan dari jarak jauh. Jika Anda mulai menguji di malam hari, itu akan berjalan bahkan saat Anda tidur.

Mengembangkan alat uji pytest berfitur lengkap dengan Python


Saat ini, ada banyak kerangka kerja dan alat untuk pengujian. Ada berbagai jenis kerangka kerja, misalnya, data-driven, kata kunci-driven, hybrid, BDD, dll. Anda dapat memilih salah satu yang paling sesuai dengan kebutuhan Anda.

Saya harus mengatakan bahwa Python dan pytest menempati ceruk besar dalam masalah ini. Python dan alat-alat terkaitnya banyak digunakan, mungkin karena lebih mudah diakses oleh orang-orang dengan sedikit pengalaman pemrograman dibandingkan dengan bahasa lain.

Kerangka pytest mudah untuk menulis tes kecil, tetapi juga skala untuk mendukung pengujian fungsional aplikasi dan perpustakaan yang canggih.

Beberapa fitur utama pytest :

  • Deteksi otomatis modul dan fungsi uji;
  • CLI yang efektif untuk meningkatkan kontrol atas apa yang ingin Anda jalankan atau lewati;
  • Ekosistem plugin pihak ketiga yang besar;
  • Jadwal - berbagai jenis, aplikasi yang berbeda;
  • Bekerja dengan kerangka pengujian unit tradisional.

Deteksi tes otomatis dan dapat dikonfigurasi


Secara default, pytest mengharapkan untuk menemukan tes dalam modul Python yang namanya dimulai dengan test_ atau diakhiri dengan _test.py . Selain itu, secara default, ia mengharapkan nama-nama fungsi tes untuk memulai dengan awalan test_ . Namun, protokol deteksi tes ini dapat diubah dengan menambahkan konfigurasi Anda sendiri ke salah satu pytest konfigurasi pytest .

 # content of pytest.ini # Example 1: have pytest look for "check" instead of "test" # can also be defined in tox.ini or setup.cfg file, although the section # name in setup.cfg files should be "tool:pytest" [pytest] python_files = check_*.py python_classes = Check python_functions = *_check 

Mari kita lihat fungsi tes yang sangat sederhana:

 class CheckClass(object): def one_check(self): x = "this" assert 'h' in x def two_check(self): x = "hello" assert hasattr(x, 'check') 

Pernahkah Anda memperhatikan sesuatu? Tidak ada assertEqual atau assertDictEqual , hanya pernyataan yang dapat diakses dan dimengerti. Tidak perlu mengimpor fungsi-fungsi ini untuk hanya membandingkan dua objek. Menegaskan adalah apa yang sudah dimiliki Python dan tidak perlu menemukan kembali roda.

Kode templat? Jangan khawatir, perlengkapan terburu-buru untuk menyelamatkan!


Lihatlah fungsi tes yang menguji operasi dasar dalam program Wallet:

 // test_wallet.py from wallet import Wallet def test_default_initial_amount(): wallet = Wallet() assert wallet.balance == 0 wallet.close() def test_setting_initial_amount(): wallet = Wallet(initial_amount=100) assert wallet.balance == 100 wallet.close() def test_wallet_add_cash(): wallet = Wallet(initial_amount=10) wallet.add_cash(amount=90) assert wallet.balance == 100 wallet.close() def test_wallet_spend_cash(): wallet = Wallet(initial_amount=20) wallet.spend_cash(amount=10) assert wallet.balance == 10 wallet.close() 

Ahem, menarik! Pernahkah Anda memperhatikan? Ada banyak kode boilerplate. Hal lain yang patut dicatat adalah bahwa tes ini melakukan hal lain selain menguji bagian fungsional, misalnya, membuat Dompet dan menutupnya dengan wallet.close() .

Sekarang mari kita lihat bagaimana Anda bisa menghilangkan kode boilerplate menggunakan pytest pytest.

 import pytest from _pytest.fixtures import SubRequest from wallet import Wallet #==================== fixtures @pytest.fixture def wallet(request: SubRequest): param = getattr(request, 'param', None) if param: prepared_wallet = Wallet(initial_amount=param[0]) else: prepared_wallet = Wallet() yield prepared_wallet prepared_wallet.close() #==================== tests def test_default_initial_amount(wallet): assert wallet.balance == 0 @pytest.mark.parametrize('wallet', [(100,)], indirect=True) def test_setting_initial_amount(wallet): assert wallet.balance == 100 @pytest.mark.parametrize('wallet', [(10,)], indirect=True) def test_wallet_add_cash(wallet): wallet.add_cash(amount=90) assert wallet.balance == 100 @pytest.mark.parametrize('wallet', [(20,)], indirect=True) def test_wallet_spend_cash(wallet): wallet.spend_cash(amount=10) assert wallet.balance == 10 

Bagus bukan? Fungsi tes sekarang kompak dan melakukan apa yang seharusnya mereka lakukan. Dompet dikonfigurasikan, dipasang, dan ditutup menggunakan wallet . Fixture tidak hanya membantu menulis kode yang dapat digunakan kembali, tetapi juga menambahkan konsep berbagi data. Jika Anda perhatikan dengan cermat, jumlah dalam wallet adalah bagian dari data uji yang disediakan secara eksternal oleh logika uji, dan tidak secara kaku dipasang di dalam fungsi.

 @pytest.mark.parametrize('wallet', [(10,)], indirect=True) 

Dalam lingkungan yang lebih terkontrol, Anda mungkin memiliki file dengan data pengujian, misalnya test-data.ini di repositori atau shell yang dapat membacanya, sementara fungsi pengujian Anda dapat memanggil berbagai shell untuk membaca data pengujian.

Namun disarankan untuk meletakkan semua perlengkapan Anda di file conftest.py khusus. Ini adalah file khusus di pytest yang memungkinkan tes untuk mendeteksi perlengkapan global.

Tapi saya punya test case yang ingin saya jalankan di dataset berbeda!


Jangan khawatir, pytest memiliki fitur keren untuk pytest parameter perlengkapan Anda. Mari kita lihat sebuah contoh.

Misalkan produk Anda memiliki CLI yang dikelola secara lokal. Selain itu, produk Anda memiliki banyak parameter default yang ditetapkan saat startup, dan Anda ingin memeriksa semua nilai parameter ini.

Anda mungkin berpikir untuk menulis test case terpisah untuk masing-masing parameter ini, tetapi dengan pytest semuanya jauh lebih sederhana!

 @pytest.mark.parametrize(β€œsetting_name, setting_value”, [('qdb_mem_usage', 'low'), ('report_crashes', 'yes'), ('stop_download_on_hang', 'no'), ('stop_download_on_disconnect', 'no'), ('reduce_connections_on_congestion', 'no'), ('global.max_web_users', '1024'), ('global.max_downloads', '5'), ('use_kernel_congestion_detection', 'no'), ('log_type', 'normal'), ('no_signature_check', 'no'), ('disable_xmlrpc', 'no'), ('disable_ntp', 'yes'), ('ssl_mode', 'tls_1_2'),])def test_settings_defaults(self, setting_name, setting_value): assert product_shell.run_command(setting_name) == \ self.”The current value for \'{0}\' is \'{1}\'.”.format(setting_name, setting_value), \ 'The {} default should be {}'.format(preference_name, preference_value) 

Keren bukan? Anda baru saja menulis 13 test case (masing-masing menetapkan nilai setting_value berbeda), dan di masa depan, jika Anda menambahkan parameter baru ke produk Anda, yang perlu Anda lakukan adalah menambahkan tuple lain.

Bagaimana pytest berintegrasi dengan pengujian antarmuka pengguna dengan uji Selenium dan API?


Nah, produk Anda mungkin memiliki beberapa antarmuka. CLI - seperti yang kami katakan di atas. Mirip dengan GUI dan API. Sebelum menggunakan produk perangkat lunak Anda, penting untuk menguji semuanya. Dalam perangkat lunak perusahaan, di mana beberapa komponen saling berhubungan dan bergantung satu sama lain, perubahan pada satu bagian dapat memengaruhi yang lain.

Ingat bahwa pytest hanyalah kerangka kerja untuk pengujian yang mudah, bukan jenis pengujian khusus. Artinya, Anda bisa membuat tes untuk GUI menggunakan Selenium atau, misalnya, tes untuk API dengan pustaka requests dari Python dan menjalankannya dengan pytest .

Misalnya, pada level tinggi, ini bisa berupa pemeriksaan struktur repositori.



Seperti yang Anda lihat pada gambar di atas, ini memberikan peluang bagus untuk memisahkan komponen:

apiobjects : Tempat yang bagus untuk membuat pembungkus untuk memanggil titik akhir API. Anda mungkin memiliki BaseAPIObject dan kelas turunan yang memenuhi persyaratan Anda.

pembantu : Anda dapat menambahkan metode pembantu Anda di sini.

lib : file perpustakaan yang dapat digunakan oleh berbagai komponen, misalnya, conftest Anda di conftest , objek pageobjects , dll.

pageobjects : PageObjects arsitektur PageObjects dapat digunakan untuk membuat kelas untuk berbagai halaman GUI. Kami menggunakan Webium , yang merupakan pustaka implementasi templat Objek Halaman untuk Python.

suites : Anda dapat menulis set cek pylint Anda sendiri untuk kode, mereka akan membantu Anda mendapatkan lebih banyak kepercayaan pada kualitas kode Anda.

tes : Anda dapat membuat katalog tes berdasarkan preferensi Anda. Ini akan membuatnya mudah untuk mengelola dan meninjau tes Anda.

Saya membawanya hanya untuk referensi, struktur repositori dan dependensi dapat diatur sesuai dengan kebutuhan pribadi Anda.

Saya punya banyak test case dan saya ingin mereka berjalan secara paralel


Anda dapat memiliki banyak test case di set Anda, dan kebetulan Anda perlu menjalankannya secara paralel dan mengurangi keseluruhan waktu pelaksanaan pengujian.

Pytest menawarkan plugin uji coba paralel mengagumkan yang disebut pytest-xdist , yang menambahkan beberapa mode eksekusi unik ke pytest dasar. Instal plugin ini menggunakan pip .

 pip install pytest-xdist 

Mari kita lihat cara kerjanya dengan sebuah contoh.

Saya memiliki repositori pengujian otomatis CloudApp untuk pengujian GUI Selenium saya. Selain itu, terus berkembang dan diperbarui dengan tes baru dan sekarang ini memiliki ratusan tes. Yang ingin saya lakukan adalah menjalankannya secara paralel dan mengurangi keseluruhan waktu pelaksanaan pengujian.

Di terminal, cukup ketik pytest di folder root proyek / folder tes. Ini akan memungkinkan Anda untuk menjalankan semua tes.

 pytest -s -v -n=2 



pytest-xdist akan menjalankan semua tes secara paralel!

Dengan cara ini, Anda juga dapat menjalankan beberapa browser secara paralel.

Laporan


Pytest hadir dengan dukungan bawaan untuk membuat file hasil pengujian yang dapat dibuka menggunakan Jenkins, Bamboo, atau server integrasi berkelanjutan lainnya. Gunakan yang berikut ini:

 pytest test/file/path β€” junitxml=path 

Ini akan membantu menghasilkan file XML yang hebat yang dapat dibuka dengan banyak parser.

Kesimpulan


Popularitas Pytest meningkat setiap tahun. Selain itu, ia memiliki dukungan komunitas yang kuat, yang memungkinkan Anda untuk mengakses banyak ekstensi, seperti pytest-django , yang akan membantu Anda menulis tes untuk aplikasi web di Django. Ingatlah bahwa pytest mendukung kasus uji yang paling bebas, jadi jika Anda menggunakan unittest , pytest harus dipertimbangkan secara lebih rinci.

Sumber



Itu saja. Sampai jumpa di lapangan !

Source: https://habr.com/ru/post/id480186/


All Articles