Tutorial dalam artikel ini akan membantu Anda menguji antarmuka web Anda. Kami akan membuat solusi pengujian antarmuka web yang kuat dan sederhana menggunakan Python , pytest , dan Selenium WebDriver . Kami akan melihat strategi untuk membangun tes dan pola yang baik untuk menulis tes otomatis yang baik. Tentu saja, proyek pengujian yang dikembangkan dapat berfungsi sebagai dasar yang baik untuk membuat kasus pengujian Anda sendiri.
Browser yang mana?
Uji pencarian DuckDuckGo dari salah satu bab sebelumnya berfungsi dengan baik ... tetapi hanya di Chrome. Mari kita lihat perlengkapannya lagi
browser:
@pytest.fixture
def browser():
driver = Chrome()
driver.implicitly_wait(10)
yield driver
driver.quit()
Jenis driver dan waktu tunggu habis di-hardcode. Untuk bukti konsep, ini mungkin bagus, tetapi uji produksi harus dapat dikonfigurasi pada waktu proses. Pengujian untuk antarmuka web seharusnya berfungsi di browser apa pun. Nilai batas waktu default harus disesuaikan jika beberapa lingkungan berjalan lebih lambat dari yang lain. Data sensitif seperti nama pengguna dan kata sandi juga tidak boleh muncul di kode sumber. Bagaimana Anda bekerja dengan data uji tersebut ?
Semua nilai ini adalah data konfigurasi untuk sistem pengujian otomatis. Mereka adalah nilai terpisah yang secara sistematis memengaruhi cara kerja otomatisasi. Data konfigurasi harus menjadi masukan dengan setiap pengujian yang dijalankan. Semua yang terkait dengan pengujian dan konfigurasi lingkungan harus diperlakukan sebagai data konfigurasi sehingga kode otomatisasi dapat digunakan kembali.
Sumber masukan
Dalam sistem pengujian otomatis, ada beberapa cara untuk membaca data masukan:
- Argumen baris perintah;
- Variabel Lingkungan;
- Sifat sistem;
- File konfigurasi;
- Permintaan API.
Sayangnya, sebagian besar framework pengujian tidak mendukung membaca data dari argumen baris perintah. Variabel lingkungan dan properti sistem sulit untuk dikelola dan berpotensi berbahaya untuk ditangani. API Layanan adalah cara terbaik untuk menggunakan input, terutama mendapatkan rahasia (seperti kata sandi) dari layanan manajemen kunci seperti AWS KMS atau Azure Key Vault . Namun, membayar untuk fungsionalitas tersebut mungkin tidak dapat diterima, dan menulis sendiri tidak bijaksana. Dalam hal ini, file konfigurasi adalah opsi terbaik.
File konfigurasi adalah file biasa yang berisi data konfigurasi. Pengujian otomatis dapat membacanya saat pengujian dijalankan dan menggunakan nilai input untuk menjalankan pengujian. Misalnya, file konfigurasi mungkin menentukan jenis browser yang digunakan sebagai perlengkapan browser dalam proyek sampel kami. Biasanya, file konfigurasi dalam format standar seperti JSON, YAML, atau INI. File tersebut juga harus rata agar dapat dengan mudah dibedakan dari file lain.
File konfigurasi kami
Mari tulis file konfigurasi untuk proyek pengujian kita. Kami akan menggunakan format JSON karena mudah digunakan, populer, dan memiliki hierarki yang jelas. Selain itu, modul json adalah pustaka standar Python yang mengubah file JSON menjadi kamus dengan mudah. Buat file baru bernama
tests/config.jsondan tambahkan kode berikut:
{
"browser": "chrome",
"wait_time": 10
}
JSON menggunakan pasangan nilai kunci. Seperti yang kami katakan, ada dua nilai konfigurasi dalam proyek kami: pemilihan browser dan waktu tunggu. Di sini "browser" adalah string dan "wait_time" adalah integer.
Membaca file konfigurasi dengan pytest
Jadwal adalah cara terbaik untuk membaca file konfigurasi menggunakan pytest. Mereka dapat digunakan untuk membaca file konfigurasi sebelum memulai pengujian, dan kemudian memasukkan nilai ke dalam pengujian atau bahkan perlengkapan lainnya. Tambahkan perlengkapan berikut ke
tests/test_web.py:
import json
@pytest.fixture(scope='session')
def config():
with open('tests/config.json') as config_file:
data = json.load(config_file)
return data
Fixture
configmembaca dan mem-parsing file tests/config.jsonke dalam kamus menggunakan modul json. Jalur file berkode keras adalah praktik yang cukup umum. Faktanya, banyak alat dan sistem otomatisasi akan memeriksa file di beberapa direktori atau terhadap pola penamaan. Ruang lingkup pertandingan ditetapkan ke "sesi", sehingga pertandingan akan berjalan sekali per sesi tes. Anda tidak perlu membaca file konfigurasi yang sama setiap kali dalam pengujian baru - ini tidak efisien!
Input konfigurasi diperlukan saat menginisialisasi WebDriver. Perbarui perlengkapan
browsersebagai berikut:
@pytest.fixture
def browser(config):
if config['browser'] == 'chrome':
driver = Chrome()
else:
raise Exception(f'"{config["browser"]}" is not a supported browser')
driver.implicitly_wait(config['wait_time'])
yield driver
driver.quit()
Perlengkapan
browsersekarang akan memiliki ketergantungan perlengkapan config. Meskipun configdiluncurkan sekali per sesi pengujian, browser akan tetap dipanggil sebelum setiap pengujian. Sekarang saya browsermemiliki rantai if-elseuntuk menentukan jenis WebDriver yang akan digunakan. Untuk saat ini, hanya Chrome yang didukung, tetapi kami akan segera menambahkan beberapa jenis lagi. Jika browser tidak terdeteksi, pengecualian akan dilempar. Batas waktu implisit juga akan mengambil nilainya dari file konfigurasi.
Karena
browsermasih mengembalikan instance WebDriver, pengujian yang menggunakannya tidak perlu difaktor ulang! Mari kita jalankan pengujian untuk memastikan file konfigurasi berfungsi:
$ pipenv run python -m pytest tests/test_web.py
============================= test session starts ==============================
platform darwin -- Python 3.7.3, pytest-4.5.0, py-1.8.0, pluggy-0.12.0
rootdir: /Users/andylpk247/Programming/automation-panda/python-webui-testing
collected 1 item
tests/test_web.py . [100%]
=========================== 1 passed in 5.00 seconds ===========================
Menambahkan browser baru
Sekarang proyek kami memiliki file konfigurasi, kami dapat menggunakannya untuk mengubah browser. Ayo jalankan pengujian di Mozilla Firefox, bukan di Google Chrome. Untuk melakukannya, unduh dan instal Firefox terbaru , lalu unduh geckodriver terbaru (driver Firefox). Pastikan itu
geckodriverjuga di jalur sistem.
Perbarui kode perlengkapan
browseruntuk bekerja dengan Firefox:
from selenium.webdriver import Chrome, Firefox
@pytest.fixture
def browser(config):
if config['browser'] == 'chrome':
driver = Chrome()
elif config['browser'] == 'firefox':
driver = Firefox()
else:
raise Exception(f'"{config["browser"]}" is not a supported browser')
driver.implicitly_wait(config['wait_time'])
yield driver
driver.quit()
Kemudian tambahkan opsi ke file konfigurasi
Β«firefoxΒ»:
{
"browser": "firefox",
"wait_time": 10
}
Sekarang mulai ulang pengujian dan Anda akan melihat jendela Firefox, bukan Chrome!
Validasi
Terlepas dari kenyataan bahwa file konfigurasi berfungsi, ada kesalahan yang signifikan dalam logika pemrosesannya: data tidak diperiksa sebelum menjalankan pengujian. Fixture
browserakan mengeluarkan pengecualian jika browser tidak dipilih dengan benar, tetapi itu akan terjadi untuk setiap tes. Akan jauh lebih efisien jika pengecualian jenis ini akan dilemparkan sekali per sesi pengujian. Selain itu, pengujian akan gagal jika kunci "browser" atau "wait_time" tidak ada di file konfigurasi . Mari perbaiki ini.
Tambahkan perlengkapan baru untuk memvalidasi pilihan browser:
@pytest.fixture(scope='session')
def config_browser(config):
if 'browser' not in config:
raise Exception('The config file does not contain "browser"')
elif config['browser'] not in ['chrome', 'firefox']:
raise Exception(f'"{config["browser"]}" is not a supported browser')
return config['browser']
Perlengkapan tersebut
config_browsertergantung pada perlengkapan konfigurasi. Juga, seperti config, ia memiliki scope = "session". Kami akan mendapatkan pengecualian jika tidak ada kunci "browser" di file konfigurasi atau jika browser yang dipilih tidak didukung. Akhirnya, ini mengembalikan browser yang dipilih sehingga tes dan perlengkapan lain dapat mengakses nilai ini dengan aman.
Berikut adalah jadwal berikut untuk validasi batas waktu:
@pytest.fixture(scope='session')
def config_wait_time(config):
return config['wait_time'] if 'wait_time' in config else 10
Jika batas waktu ditentukan dalam file konfigurasi, fixture
config_wait_timeakan mengembalikannya. Jika tidak, ini akan mengembalikan 10 detik secara default.
Perbarui perlengkapan
browserlagi untuk menggunakan perlengkapan validasi baru:
@pytest.fixture
def browser(config_browser, config_wait_time):
if config_browser == 'chrome':
driver = Chrome()
elif config_browser == 'firefox':
driver = Firefox()
else:
raise Exception(f'"{config_browser}" is not a supported browser')
driver.implicitly_wait(config_wait_time)
yield driver
driver.quit()
Menulis fungsi fixture terpisah untuk setiap nilai data konfigurasi membuatnya sederhana, jelas, dan spesifik. Mereka juga memungkinkan Anda untuk mendeklarasikan hanya nilai-nilai yang diperlukan untuk mengirim permintaan.
Jalankan pengujian dan pastikan semuanya berfungsi:
$ pipenv run python -m pytest tests/test_web.py
============================= test session starts ==============================
platform darwin -- Python 3.7.3, pytest-4.5.0, py-1.8.0, pluggy-0.12.0
rootdir: /Users/andylpk247/Programming/automation-panda/python-webui-testing
collected 1 item
tests/test_web.py . [100%]
=========================== 1 passed in 4.58 seconds ===========================
Dan itu keren! Namun, untuk membuat validasi lebih realistis, Anda harus rumit. Mari kita ubah nilai "browser" menjadi "safari" - browser yang tidak didukung.
$ pipenv run python -m pytest tests/test_web.py
============================= test session starts ==============================
platform darwin -- Python 3.7.3, pytest-4.5.0, py-1.8.0, pluggy-0.12.0
rootdir: /Users/andylpk247/Programming/automation-panda/python-webui-testing
collected 1 item
tests/test_web.py E [100%]
==================================== ERRORS ====================================
________________ ERROR at setup of test_basic_duckduckgo_search ________________
config = {'browser': 'safari', 'wait_time': 10}
@pytest.fixture(scope='session')
def config_browser(config):
# Validate and return the browser choice from the config data
if 'browser' not in config:
raise Exception('The config file does not contain "browser"')
elif config['browser'] not in SUPPORTED_BROWSERS:
> raise Exception(f'"{config["browser"]}" is not a supported browser')
E Exception: "safari" is not a supported browser
tests/conftest.py:30: Exception
=========================== 1 error in 0.09 seconds ============================
Wow! Kesalahan tersebut dengan jelas menunjukkan mengapa itu muncul. Sekarang, apa yang terjadi jika kita menghapus pilihan browser dari file konfigurasi?
$ pipenv run python -m pytest tests/test_web.py
============================= test session starts ==============================
platform darwin -- Python 3.7.3, pytest-4.5.0, py-1.8.0, pluggy-0.12.0
rootdir: /Users/andylpk247/Programming/automation-panda/python-webui-testing
collected 1 item
tests/test_web.py E [100%]
==================================== ERRORS ====================================
________________ ERROR at setup of test_basic_duckduckgo_search ________________
config = {'wait_time': 10}
@pytest.fixture(scope='session')
def config_browser(config):
# Validate and return the browser choice from the config data
if 'browser' not in config:
> raise Exception('The config file does not contain "browser"')
E Exception: The config file does not contain "browser"
tests/conftest.py:28: Exception
=========================== 1 error in 0.10 seconds ============================
Luar biasa! Pesan kesalahan bermanfaat lainnya. Untuk pengujian terakhir, mari tambahkan pilihan browser, tetapi hapus waktu tunggu:
$ pipenv run python -m pytest tests/test_web.py
============================= test session starts ==============================
platform darwin -- Python 3.7.3, pytest-4.5.0, py-1.8.0, pluggy-0.12.0
rootdir: /Users/andylpk247/Programming/automation-panda/python-webui-testing
collected 1 item
tests/test_web.py . [100%]
=========================== 1 passed in 4.64 seconds ===========================
Tes harus berjalan karena waktu tunggu bersifat opsional. Nah, perubahan yang kami buat bermanfaat! Ingatlah bahwa terkadang Anda perlu menguji tes Anda juga .
Ujian akhir
Ada dua hal kecil lagi yang dapat kita lakukan untuk membuat kode pengujian lebih bersih. Pertama, mari pindahkan perlengkapan web kita ke sebuah file
conftest.pysehingga semua tes dapat menggunakannya, tidak hanya tes di tes / test_web.py. Kedua, mari kita tarik beberapa nilai literal ke dalam variabel modul.
Buat file baru bernama
tests/conftest.pydengan kode berikut:
import json
import pytest
from selenium.webdriver import Chrome, Firefox
CONFIG_PATH = 'tests/config.json'
DEFAULT_WAIT_TIME = 10
SUPPORTED_BROWSERS = ['chrome', 'firefox']
@pytest.fixture(scope='session')
def config():
# Read the JSON config file and returns it as a parsed dict
with open(CONFIG_PATH) as config_file:
data = json.load(config_file)
return data
@pytest.fixture(scope='session')
def config_browser(config):
# Validate and return the browser choice from the config data
if 'browser' not in config:
raise Exception('The config file does not contain "browser"')
elif config['browser'] not in SUPPORTED_BROWSERS:
raise Exception(f'"{config["browser"]}" is not a supported browser')
return config['browser']
@pytest.fixture(scope='session')
def config_wait_time(config):
# Validate and return the wait time from the config data
return config['wait_time'] if 'wait_time' in config else DEFAULT_WAIT_TIME
@pytest.fixture
def browser(config_browser, config_wait_time):
# Initialize WebDriver
if config_browser == 'chrome':
driver = Chrome()
elif config_browser == 'firefox':
driver = Firefox()
else:
raise Exception(f'"{config_browser}" is not a supported browser')
# Wait implicitly for elements to be ready before attempting interactions
driver.implicitly_wait(config_wait_time)
# Return the driver object at the end of setup
yield driver
# For cleanup, quit the driver
driver.quit()
Konten lengkap
tests/test_web.pysekarang harus lebih sederhana dan lebih bersih:
import pytest
from pages.result import DuckDuckGoResultPage
from pages.search import DuckDuckGoSearchPage
def test_basic_duckduckgo_search(browser):
# Set up test case data
PHRASE = 'panda'
# Search for the phrase
search_page = DuckDuckGoSearchPage(browser)
search_page.load()
search_page.search(PHRASE)
# Verify that results appear
result_page = DuckDuckGoResultPage(browser)
assert result_page.link_div_count() > 0
assert result_page.phrase_result_count(PHRASE) > 0
assert result_page.search_input_value() == PHRASE
Nah, ini sudah menjadi gaya Python!
Apa berikutnya?
Jadi, kode sampel untuk proyek pengujian kami sudah selesai. Anda dapat menggunakannya sebagai dasar untuk membuat pengujian baru. Anda juga dapat menemukan contoh terakhir proyek di GitHub . Namun, kenyataan bahwa kita telah selesai menulis kode tidak berarti kita telah menyelesaikan pelatihan. Di artikel mendatang, kita akan berbicara tentang cara membawa otomatisasi pengujian Python ke tingkat selanjutnya!