Python利用pytest和selenium實(shí)現(xiàn)自動(dòng)化測(cè)試完整指南
前言
自動(dòng)化測(cè)試是現(xiàn)代軟件開發(fā)中不可或缺的一環(huán)。Python作為一門簡(jiǎn)潔優(yōu)雅的編程語言,配合pytest測(cè)試框架和selenium自動(dòng)化工具,為我們提供了強(qiáng)大的自動(dòng)化測(cè)試解決方案。
本教程將從零開始,帶領(lǐng)大家掌握Python自動(dòng)化測(cè)試的核心技能,通過實(shí)戰(zhàn)項(xiàng)目學(xué)會(huì)如何構(gòu)建穩(wěn)定、高效的自動(dòng)化測(cè)試體系。
環(huán)境搭建
安裝Python和依賴包
# 創(chuàng)建虛擬環(huán)境 python -m venv test_env source test_env/bin/activate # Windows: test_env\Scripts\activate # 安裝核心依賴 pip install pytest selenium webdriver-manager pytest-html allure-pytest
瀏覽器驅(qū)動(dòng)配置
# 使用webdriver-manager自動(dòng)管理驅(qū)動(dòng)
from webdriver_manager.chrome import ChromeDriverManager
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
def setup_driver():
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
return driver
項(xiàng)目結(jié)構(gòu)搭建
automation_project/
├── tests/
│ ├── __init__.py
│ ├── test_login.py
│ └── test_search.py
├── pages/
│ ├── __init__.py
│ ├── base_page.py
│ └── login_page.py
├── utils/
│ ├── __init__.py
│ └── config.py
├── drivers/
├── reports/
├── conftest.py
├── pytest.ini
└── requirements.txt
pytest基礎(chǔ)教程
pytest核心概念
pytest是Python中最流行的測(cè)試框架,具有以下特點(diǎn):
- 簡(jiǎn)單易用的斷言語法
- 豐富的插件生態(tài)系統(tǒng)
- 強(qiáng)大的fixture機(jī)制
- 靈活的測(cè)試發(fā)現(xiàn)和執(zhí)行
基礎(chǔ)測(cè)試示例
# test_basic.py
import pytest
def test_simple_assert():
"""基礎(chǔ)斷言測(cè)試"""
assert 1 + 1 == 2
def test_string_operations():
"""字符串操作測(cè)試"""
text = "Hello, World!"
assert "Hello" in text
assert text.startswith("Hello")
assert text.endswith("!")
class TestCalculator:
"""測(cè)試類示例"""
def test_addition(self):
assert 2 + 3 == 5
def test_division(self):
assert 10 / 2 == 5
def test_division_by_zero(self):
with pytest.raises(ZeroDivisionError):
10 / 0
fixture機(jī)制深入
# conftest.py
import pytest
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
@pytest.fixture(scope="session")
def driver():
"""會(huì)話級(jí)別的瀏覽器驅(qū)動(dòng)"""
options = webdriver.ChromeOptions()
options.add_argument("--headless") # 無頭模式
driver = webdriver.Chrome(
service=Service(ChromeDriverManager().install()),
options=options
)
yield driver
driver.quit()
@pytest.fixture
def test_data():
"""測(cè)試數(shù)據(jù)fixture"""
return {
"username": "test@example.com",
"password": "password123"
}
參數(shù)化測(cè)試
# test_parametrize.py
import pytest
@pytest.mark.parametrize("a,b,expected", [
(2, 3, 5),
(1, 1, 2),
(0, 5, 5),
(-1, 1, 0)
])
def test_addition(a, b, expected):
assert a + b == expected
@pytest.mark.parametrize("url", [
"https://www.baidu.com",
"https://www.google.com"
])
def test_website_accessibility(driver, url):
driver.get(url)
assert driver.title
selenium基礎(chǔ)教程
元素定位策略
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class ElementLocator:
"""元素定位封裝類"""
def __init__(self, driver):
self.driver = driver
self.wait = WebDriverWait(driver, 10)
def find_element_safely(self, locator):
"""安全查找元素"""
try:
element = self.wait.until(EC.presence_of_element_located(locator))
return element
except TimeoutException:
print(f"元素定位失敗: {locator}")
return None
def click_element(self, locator):
"""點(diǎn)擊元素"""
element = self.wait.until(EC.element_to_be_clickable(locator))
element.click()
def input_text(self, locator, text):
"""輸入文本"""
element = self.find_element_safely(locator)
if element:
element.clear()
element.send_keys(text)
常用操作封裝
# utils/selenium_helper.py
from selenium.webdriver.support.ui import Select
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
class SeleniumHelper:
"""Selenium操作助手類"""
def __init__(self, driver):
self.driver = driver
def scroll_to_element(self, element):
"""滾動(dòng)到指定元素"""
self.driver.execute_script("arguments[0].scrollIntoView();", element)
def select_dropdown_by_text(self, locator, text):
"""通過文本選擇下拉框"""
select = Select(self.driver.find_element(*locator))
select.select_by_visible_text(text)
def hover_element(self, element):
"""鼠標(biāo)懸停"""
actions = ActionChains(self.driver)
actions.move_to_element(element).perform()
def switch_to_iframe(self, iframe_locator):
"""切換到iframe"""
iframe = self.driver.find_element(*iframe_locator)
self.driver.switch_to.frame(iframe)
def take_screenshot(self, filename):
"""截圖"""
self.driver.save_screenshot(f"screenshots/{filename}")
pytest + selenium實(shí)戰(zhàn)項(xiàng)目
實(shí)戰(zhàn)項(xiàng)目:電商網(wǎng)站測(cè)試
讓我們以一個(gè)電商網(wǎng)站為例,構(gòu)建完整的自動(dòng)化測(cè)試項(xiàng)目。
配置文件設(shè)置
# utils/config.py
class Config:
"""測(cè)試配置類"""
BASE_URL = "https://example-shop.com"
TIMEOUT = 10
BROWSER = "chrome"
HEADLESS = False
# 測(cè)試賬戶信息
TEST_USER = {
"email": "test@example.com",
"password": "password123"
}
# 測(cè)試數(shù)據(jù)
TEST_PRODUCT = {
"name": "iPhone 14",
"price": "999.99"
}
基礎(chǔ)頁面類
# pages/base_page.py
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
class BasePage:
"""基礎(chǔ)頁面類"""
def __init__(self, driver):
self.driver = driver
self.wait = WebDriverWait(driver, 10)
def open(self, url):
"""打開頁面"""
self.driver.get(url)
def find_element(self, locator):
"""查找元素"""
return self.wait.until(EC.presence_of_element_located(locator))
def click(self, locator):
"""點(diǎn)擊元素"""
element = self.wait.until(EC.element_to_be_clickable(locator))
element.click()
def input_text(self, locator, text):
"""輸入文本"""
element = self.find_element(locator)
element.clear()
element.send_keys(text)
def get_text(self, locator):
"""獲取元素文本"""
element = self.find_element(locator)
return element.text
def is_element_visible(self, locator):
"""檢查元素是否可見"""
try:
self.wait.until(EC.visibility_of_element_located(locator))
return True
except:
return False
登錄頁面類
# pages/login_page.py
from selenium.webdriver.common.by import By
from pages.base_page import BasePage
class LoginPage(BasePage):
"""登錄頁面"""
# 頁面元素定位
EMAIL_INPUT = (By.ID, "email")
PASSWORD_INPUT = (By.ID, "password")
LOGIN_BUTTON = (By.XPATH, "http://button[@type='submit']")
ERROR_MESSAGE = (By.CLASS_NAME, "error-message")
SUCCESS_MESSAGE = (By.CLASS_NAME, "success-message")
def login(self, email, password):
"""執(zhí)行登錄操作"""
self.input_text(self.EMAIL_INPUT, email)
self.input_text(self.PASSWORD_INPUT, password)
self.click(self.LOGIN_BUTTON)
def get_error_message(self):
"""獲取錯(cuò)誤信息"""
if self.is_element_visible(self.ERROR_MESSAGE):
return self.get_text(self.ERROR_MESSAGE)
return None
def is_login_successful(self):
"""檢查登錄是否成功"""
return self.is_element_visible(self.SUCCESS_MESSAGE)
登錄測(cè)試用例
# tests/test_login.py
import pytest
from pages.login_page import LoginPage
from utils.config import Config
class TestLogin:
"""登錄功能測(cè)試類"""
@pytest.fixture(autouse=True)
def setup(self, driver):
"""測(cè)試前置條件"""
self.driver = driver
self.login_page = LoginPage(driver)
self.login_page.open(f"{Config.BASE_URL}/login")
def test_valid_login(self):
"""測(cè)試有效登錄"""
self.login_page.login(
Config.TEST_USER["email"],
Config.TEST_USER["password"]
)
assert self.login_page.is_login_successful()
@pytest.mark.parametrize("email,password,expected_error", [
("", "password123", "郵箱不能為空"),
("invalid-email", "password123", "郵箱格式不正確"),
("test@example.com", "", "密碼不能為空"),
("wrong@example.com", "wrongpass", "用戶名或密碼錯(cuò)誤")
])
def test_invalid_login(self, email, password, expected_error):
"""測(cè)試無效登錄"""
self.login_page.login(email, password)
error_message = self.login_page.get_error_message()
assert expected_error in error_message
def test_login_form_elements(self):
"""測(cè)試登錄表單元素存在性"""
assert self.login_page.is_element_visible(self.login_page.EMAIL_INPUT)
assert self.login_page.is_element_visible(self.login_page.PASSWORD_INPUT)
assert self.login_page.is_element_visible(self.login_page.LOGIN_BUTTON)
商品搜索測(cè)試
# pages/search_page.py
from selenium.webdriver.common.by import By
from pages.base_page import BasePage
class SearchPage(BasePage):
"""搜索頁面"""
SEARCH_INPUT = (By.NAME, "search")
SEARCH_BUTTON = (By.CLASS_NAME, "search-btn")
SEARCH_RESULTS = (By.CLASS_NAME, "product-item")
NO_RESULTS_MESSAGE = (By.CLASS_NAME, "no-results")
PRODUCT_TITLE = (By.CLASS_NAME, "product-title")
def search_product(self, keyword):
"""搜索商品"""
self.input_text(self.SEARCH_INPUT, keyword)
self.click(self.SEARCH_BUTTON)
def get_search_results_count(self):
"""獲取搜索結(jié)果數(shù)量"""
results = self.driver.find_elements(*self.SEARCH_RESULTS)
return len(results)
def get_first_product_title(self):
"""獲取第一個(gè)商品標(biāo)題"""
return self.get_text(self.PRODUCT_TITLE)
# tests/test_search.py
import pytest
from pages.search_page import SearchPage
from utils.config import Config
class TestSearch:
"""搜索功能測(cè)試類"""
@pytest.fixture(autouse=True)
def setup(self, driver):
self.driver = driver
self.search_page = SearchPage(driver)
self.search_page.open(Config.BASE_URL)
def test_valid_search(self):
"""測(cè)試有效搜索"""
self.search_page.search_product("iPhone")
assert self.search_page.get_search_results_count() > 0
def test_search_no_results(self):
"""測(cè)試無結(jié)果搜索"""
self.search_page.search_product("不存在的商品")
assert self.search_page.is_element_visible(self.search_page.NO_RESULTS_MESSAGE)
@pytest.mark.parametrize("keyword", [
"iPhone", "Samsung", "小米", "華為"
])
def test_multiple_searches(self, keyword):
"""測(cè)試多個(gè)關(guān)鍵詞搜索"""
self.search_page.search_product(keyword)
results_count = self.search_page.get_search_results_count()
assert results_count >= 0 # 至少返回0個(gè)結(jié)果
頁面對(duì)象模式(POM)
頁面對(duì)象模式是自動(dòng)化測(cè)試中的重要設(shè)計(jì)模式,它將頁面元素和操作封裝在獨(dú)立的類中。
完整的POM實(shí)現(xiàn)
# pages/product_page.py
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
from pages.base_page import BasePage
class ProductPage(BasePage):
"""商品詳情頁"""
# 商品信息元素
PRODUCT_TITLE = (By.H1, "product-title")
PRODUCT_PRICE = (By.CLASS_NAME, "price")
PRODUCT_DESCRIPTION = (By.CLASS_NAME, "description")
# 購(gòu)買相關(guān)元素
QUANTITY_SELECT = (By.NAME, "quantity")
ADD_TO_CART_BUTTON = (By.ID, "add-to-cart")
CART_SUCCESS_MESSAGE = (By.CLASS_NAME, "cart-success")
# 評(píng)論相關(guān)元素
REVIEWS_SECTION = (By.ID, "reviews")
REVIEW_INPUT = (By.NAME, "review")
SUBMIT_REVIEW_BUTTON = (By.ID, "submit-review")
def get_product_info(self):
"""獲取商品信息"""
return {
"title": self.get_text(self.PRODUCT_TITLE),
"price": self.get_text(self.PRODUCT_PRICE),
"description": self.get_text(self.PRODUCT_DESCRIPTION)
}
def add_to_cart(self, quantity=1):
"""添加到購(gòu)物車"""
# 選擇數(shù)量
quantity_select = Select(self.find_element(self.QUANTITY_SELECT))
quantity_select.select_by_value(str(quantity))
# 點(diǎn)擊添加到購(gòu)物車
self.click(self.ADD_TO_CART_BUTTON)
# 等待成功消息
return self.is_element_visible(self.CART_SUCCESS_MESSAGE)
def submit_review(self, review_text):
"""提交評(píng)論"""
self.input_text(self.REVIEW_INPUT, review_text)
self.click(self.SUBMIT_REVIEW_BUTTON)
購(gòu)物車頁面測(cè)試
# tests/test_cart.py
import pytest
from pages.product_page import ProductPage
from pages.cart_page import CartPage
from utils.config import Config
class TestShoppingCart:
"""購(gòu)物車功能測(cè)試"""
@pytest.fixture(autouse=True)
def setup(self, driver):
self.driver = driver
self.product_page = ProductPage(driver)
self.cart_page = CartPage(driver)
def test_add_single_product_to_cart(self):
"""測(cè)試添加單個(gè)商品到購(gòu)物車"""
# 打開商品頁面
self.product_page.open(f"{Config.BASE_URL}/product/1")
# 添加到購(gòu)物車
success = self.product_page.add_to_cart(quantity=1)
assert success
# 驗(yàn)證購(gòu)物車
self.cart_page.open(f"{Config.BASE_URL}/cart")
assert self.cart_page.get_cart_items_count() == 1
def test_add_multiple_quantities(self):
"""測(cè)試添加多數(shù)量商品"""
self.product_page.open(f"{Config.BASE_URL}/product/1")
success = self.product_page.add_to_cart(quantity=3)
assert success
self.cart_page.open(f"{Config.BASE_URL}/cart")
total_quantity = self.cart_page.get_total_quantity()
assert total_quantity == 3
def test_cart_total_calculation(self):
"""測(cè)試購(gòu)物車總價(jià)計(jì)算"""
# 添加多個(gè)商品
products = [
{"id": 1, "quantity": 2, "price": 99.99},
{"id": 2, "quantity": 1, "price": 149.99}
]
expected_total = 0
for product in products:
self.product_page.open(f"{Config.BASE_URL}/product/{product['id']}")
self.product_page.add_to_cart(product["quantity"])
expected_total += product["price"] * product["quantity"]
self.cart_page.open(f"{Config.BASE_URL}/cart")
actual_total = self.cart_page.get_total_price()
assert actual_total == expected_total
測(cè)試報(bào)告生成
HTML報(bào)告配置
# pytest.ini
[tool:pytest]
minversion = 6.0
addopts = -v --strict-markers --html=reports/report.html --self-contained-html
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
markers =
smoke: 冒煙測(cè)試
regression: 回歸測(cè)試
slow: 慢速測(cè)試
Allure報(bào)告集成
# conftest.py 添加allure配置
import allure
import pytest
from selenium import webdriver
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
"""生成測(cè)試報(bào)告鉤子"""
outcome = yield
report = outcome.get_result()
if report.when == "call" and report.failed:
# 測(cè)試失敗時(shí)自動(dòng)截圖
driver = item.funcargs.get('driver')
if driver:
allure.attach(
driver.get_screenshot_as_png(),
name="失敗截圖",
attachment_type=allure.attachment_type.PNG
)
# 在測(cè)試中使用allure裝飾器
import allure
class TestLoginWithAllure:
"""帶Allure報(bào)告的登錄測(cè)試"""
@allure.epic("用戶管理")
@allure.feature("用戶登錄")
@allure.story("正常登錄流程")
@allure.severity(allure.severity_level.CRITICAL)
def test_valid_login_with_allure(self, driver):
"""測(cè)試有效登錄 - Allure版本"""
with allure.step("打開登錄頁面"):
login_page = LoginPage(driver)
login_page.open(f"{Config.BASE_URL}/login")
with allure.step("輸入登錄憑證"):
login_page.login(
Config.TEST_USER["email"],
Config.TEST_USER["password"]
)
with allure.step("驗(yàn)證登錄結(jié)果"):
assert login_page.is_login_successful()
allure.attach(
driver.get_screenshot_as_png(),
name="登錄成功截圖",
attachment_type=allure.attachment_type.PNG
)
持續(xù)集成配置
GitHub Actions配置
# .github/workflows/test.yml
name: 自動(dòng)化測(cè)試
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: 設(shè)置Python環(huán)境
uses: actions/setup-python@v3
with:
python-version: '3.9'
- name: 安裝Chrome
uses: browser-actions/setup-chrome@latest
- name: 安裝依賴
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: 運(yùn)行測(cè)試
run: |
pytest tests/ --html=reports/report.html --alluredir=allure-results
- name: 生成Allure報(bào)告
uses: simple-elf/allure-report-action@master
if: always()
with:
allure_results: allure-results
allure_history: allure-history
- name: 上傳測(cè)試報(bào)告
uses: actions/upload-artifact@v3
if: always()
with:
name: test-reports
path: |
reports/
allure-report/
Docker配置
# Dockerfile
FROM python:3.9-slim
# 安裝系統(tǒng)依賴
RUN apt-get update && apt-get install -y \
wget \
gnupg \
unzip \
curl
# 安裝Chrome
RUN wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list \
&& apt-get update \
&& apt-get install -y google-chrome-stable
# 設(shè)置工作目錄
WORKDIR /app
# 復(fù)制項(xiàng)目文件
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
# 運(yùn)行測(cè)試
CMD ["pytest", "tests/", "--html=reports/report.html"]
最佳實(shí)踐和進(jìn)階技巧
測(cè)試數(shù)據(jù)管理
# utils/test_data.py
import json
import yaml
from pathlib import Path
class TestDataManager:
"""測(cè)試數(shù)據(jù)管理器"""
def __init__(self, data_dir="test_data"):
self.data_dir = Path(data_dir)
def load_json_data(self, filename):
"""加載JSON測(cè)試數(shù)據(jù)"""
file_path = self.data_dir / f"{filename}.json"
with open(file_path, 'r', encoding='utf-8') as f:
return json.load(f)
def load_yaml_data(self, filename):
"""加載YAML測(cè)試數(shù)據(jù)"""
file_path = self.data_dir / f"{filename}.yaml"
with open(file_path, 'r', encoding='utf-8') as f:
return yaml.safe_load(f)
# test_data/login_data.yaml
valid_users:
- email: "user1@example.com"
password: "password123"
expected_result: "success"
- email: "user2@example.com"
password: "password456"
expected_result: "success"
invalid_users:
- email: ""
password: "password123"
expected_error: "郵箱不能為空"
- email: "invalid-email"
password: "password123"
expected_error: "郵箱格式不正確"
失敗重試機(jī)制
# conftest.py
import pytest
@pytest.fixture(autouse=True)
def retry_failed_tests(request):
"""失敗測(cè)試重試機(jī)制"""
if request.node.rep_call.failed:
# 重試邏輯
pass
# 使用pytest-rerunfailures插件
# pip install pytest-rerunfailures
# pytest --reruns 3 --reruns-delay 2
并行測(cè)試執(zhí)行
# 安裝pytest-xdist # pip install pytest-xdist # 并行執(zhí)行測(cè)試 # pytest -n auto # 自動(dòng)檢測(cè)CPU核心數(shù) # pytest -n 4 # 使用4個(gè)進(jìn)程
測(cè)試環(huán)境管理
# utils/environment.py
import os
from enum import Enum
class Environment(Enum):
DEV = "dev"
TEST = "test"
STAGING = "staging"
PROD = "prod"
class EnvironmentConfig:
"""環(huán)境配置管理"""
def __init__(self):
self.current_env = Environment(os.getenv('TEST_ENV', 'test'))
def get_base_url(self):
"""獲取當(dāng)前環(huán)境的基礎(chǔ)URL"""
urls = {
Environment.DEV: "http://dev.example.com",
Environment.TEST: "http://test.example.com",
Environment.STAGING: "http://staging.example.com",
Environment.PROD: "http://example.com"
}
return urls[self.current_env]
def get_database_config(self):
"""獲取數(shù)據(jù)庫配置"""
configs = {
Environment.TEST: {
"host": "test-db.example.com",
"database": "test_db"
},
Environment.STAGING: {
"host": "staging-db.example.com",
"database": "staging_db"
}
}
return configs.get(self.current_env, {})
性能測(cè)試集成
# tests/test_performance.py
import time
import pytest
from selenium.webdriver.support.ui import WebDriverWait
class TestPerformance:
"""性能測(cè)試"""
def test_page_load_time(self, driver):
"""測(cè)試頁面加載時(shí)間"""
start_time = time.time()
driver.get("https://example.com")
WebDriverWait(driver, 10).until(
lambda d: d.execute_script("return document.readyState") == "complete"
)
load_time = time.time() - start_time
assert load_time < 5.0, f"頁面加載時(shí)間過長(zhǎng): {load_time}秒"
def test_search_response_time(self, driver, search_page):
"""測(cè)試搜索響應(yīng)時(shí)間"""
search_page.open("https://example.com")
start_time = time.time()
search_page.search_product("iPhone")
# 等待搜索結(jié)果出現(xiàn)
WebDriverWait(driver, 10).until(
lambda d: len(d.find_elements(*search_page.SEARCH_RESULTS)) > 0
)
response_time = time.time() - start_time
assert response_time < 3.0, f"搜索響應(yīng)時(shí)間過長(zhǎng): {response_time}秒"
數(shù)據(jù)庫驗(yàn)證
# utils/database.py
import sqlite3
import pymongo
from contextlib import contextmanager
class DatabaseHelper:
"""數(shù)據(jù)庫操作助手"""
def __init__(self, db_config):
self.config = db_config
@contextmanager
def get_connection(self):
"""獲取數(shù)據(jù)庫連接"""
if self.config['type'] == 'sqlite':
conn = sqlite3.connect(self.config['path'])
elif self.config['type'] == 'mysql':
import mysql.connector
conn = mysql.connector.connect(**self.config)
try:
yield conn
finally:
conn.close()
def verify_user_created(self, email):
"""驗(yàn)證用戶是否創(chuàng)建成功"""
with self.get_connection() as conn:
cursor = conn.cursor()
cursor.execute("SELECT * FROM users WHERE email = ?", (email,))
result = cursor.fetchone()
return result is not None
# 在測(cè)試中使用數(shù)據(jù)庫驗(yàn)證
def test_user_registration_with_db_verification(driver, db_helper):
"""測(cè)試用戶注冊(cè)并驗(yàn)證數(shù)據(jù)庫"""
# 執(zhí)行注冊(cè)操作
registration_page = RegistrationPage(driver)
test_email = f"test_{int(time.time())}@example.com"
registration_page.register_user(
email=test_email,
password="password123"
)
# 驗(yàn)證UI顯示成功
assert registration_page.is_registration_successful()
# 驗(yàn)證數(shù)據(jù)庫中確實(shí)創(chuàng)建了用戶
assert db_helper.verify_user_created(test_email)
總結(jié)
本教程全面介紹了使用pytest和selenium進(jìn)行Python自動(dòng)化測(cè)試的完整流程,從環(huán)境搭建到高級(jí)技巧,涵蓋了實(shí)際項(xiàng)目中的各個(gè)方面。
關(guān)鍵要點(diǎn)回顧
- 環(huán)境搭建: 正確配置Python環(huán)境、瀏覽器驅(qū)動(dòng)和項(xiàng)目結(jié)構(gòu)
- pytest框架: 掌握基礎(chǔ)測(cè)試、fixture機(jī)制和參數(shù)化測(cè)試
- selenium操作: 學(xué)會(huì)元素定位、常用操作和等待機(jī)制
- 頁面對(duì)象模式: 使用POM提高代碼復(fù)用性和維護(hù)性
- 測(cè)試報(bào)告: 生成專業(yè)的HTML和Allure測(cè)試報(bào)告
- 持續(xù)集成: 配置CI/CD流程實(shí)現(xiàn)自動(dòng)化測(cè)試
- 最佳實(shí)踐: 應(yīng)用進(jìn)階技巧提升測(cè)試質(zhì)量和效率
以上就是Python利用pytest和selenium實(shí)現(xiàn)自動(dòng)化測(cè)試完整指南的詳細(xì)內(nèi)容,更多關(guān)于Python自動(dòng)化測(cè)試的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Python?pytest自動(dòng)化測(cè)試庫十個(gè)強(qiáng)大用法示例
- 使用python+requests+pytest實(shí)現(xiàn)接口自動(dòng)化
- python使用pytest接口自動(dòng)化測(cè)試的使用
- Python Selenium自動(dòng)化實(shí)現(xiàn)網(wǎng)頁操控
- Python利用Selenium進(jìn)行網(wǎng)頁自動(dòng)化與動(dòng)態(tài)內(nèi)容抓取操作
- Python使用Selenium批量自動(dòng)化獲取并下載圖片的方法
- Python使用Selenium進(jìn)行Web自動(dòng)化測(cè)試
相關(guān)文章
python求最大值,不使用內(nèi)置函數(shù)的實(shí)現(xiàn)方法
今天小編就為大家分享一篇python求最大值,不使用內(nèi)置函數(shù)的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-07-07
TensorFlow自定義損失函數(shù)來預(yù)測(cè)商品銷售量
這篇文章主要介紹了TensorFlow自定義損失函數(shù)——預(yù)測(cè)商品銷售量,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02
Python連接HDFS實(shí)現(xiàn)文件上傳下載及Pandas轉(zhuǎn)換文本文件到CSV操作
這篇文章主要介紹了Python連接HDFS實(shí)現(xiàn)文件上傳下載及Pandas轉(zhuǎn)換文本文件到CSV操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-06-06
6個(gè)實(shí)用的Python自動(dòng)化腳本詳解
每天你都可能會(huì)執(zhí)行許多重復(fù)的任務(wù),例如閱讀 pdf、播放音樂、查看天氣、打開書簽、清理文件夾等等,使用自動(dòng)化腳本,就無需手動(dòng)一次又一次地完成這些任務(wù),非常方便??旄S小編一起試一試吧2022-01-01
Python使用Selenium實(shí)現(xiàn)模擬登錄的示例代碼
Selenium(本文基于python3.8)是一個(gè)功能強(qiáng)大的自動(dòng)化測(cè)試工具,它可以用于模擬用戶在瀏覽器中的行為,比如點(diǎn)擊、輸入、滾動(dòng)等等,本教程將詳細(xì)介紹如何使用Python編寫一個(gè)模擬登錄地爬蟲,使用XPath等多種元素匹配方法,需要的朋友可以參考下2023-08-08

