Selenium 自动化测试教程

Selenium 自动化测试教程

第1章 项目创建与环境搭建

1.1 环境准备

  • 操作系统:Windows 10/11
  • Python 版本:3.12+
  • 浏览器:Microsoft Edge

1.2 创建虚拟环境

powershell 复制代码
# 创建虚拟环境
python -m venv .venv

# 激活虚拟环境
.venv\Scripts\Activate.ps1

# 升级 pip
python -m pip install --upgrade pip

1.3 安装依赖

powershell 复制代码
pip install selenium webdriver-manager

1.4 项目结构

复制代码
test/
├── .venv/                  # 虚拟环境
├── specified_directory/     # 运费计算测试
├── ecommerce_cart/          # 电商购物车测试
├── online_registration/     # 在线注册测试
├── flight_search/           # 航班查询测试
├── bank_transfer/           # 银行转账测试
├── online_education/        # 在线教育课程报名测试
└── selenium_automation_tutorial.md  # 本教程

第2章 基础案例:运费计算

2.1 场景说明

某快递公司官网提供"运费预估"功能。用户需输入寄件重量(公斤),选择包裹类型(普通件/易碎品),并勾选附加服务(是否保价、是否加急)。点击"计算运费"后,页面将显示预估运费。

2.2 网页实现

创建 shipping_calculator.html 文件:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>运费预估</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 500px;
            margin: 0 auto;
            padding: 20px;
        }
        .form-group {
            margin-bottom: 15px;
        }
        label {
            display: block;
            margin-bottom: 5px;
        }
        input[type="text"] {
            width: 100%;
            padding: 8px;
            box-sizing: border-box;
        }
        .radio-group, .checkbox-group {
            margin-top: 5px;
        }
        .radio-group label, .checkbox-group label {
            display: inline;
            margin-right: 15px;
        }
        button {
            background-color: #4CAF50;
            color: white;
            padding: 10px 20px;
            border: none;
            cursor: pointer;
        }
        button:hover {
            background-color: #45a049;
        }
        #result {
            margin-top: 20px;
            font-size: 24px;
            font-weight: bold;
            color: #333;
        }
    </style>
</head>
<body>
    <h1>运费预估</h1>
    <form id="shipping-form">
        <div class="form-group">
            <label for="weight">寄件重量(公斤):</label>
            <input type="text" id="weight" name="weight" placeholder="请输入重量">
        </div>

        <div class="form-group">
            <label>包裹类型:</label>
            <div class="radio-group">
                <input type="radio" id="normal" name="package_type" value="normal" checked>
                <label for="normal">普通件</label>
                <input type="radio" id="fragile" name="package_type" value="fragile">
                <label for="fragile">易碎品</label>
            </div>
        </div>

        <div class="form-group">
            <label>附加服务:</label>
            <div class="checkbox-group">
                <input type="checkbox" id="insurance" name="insurance" value="1">
                <label for="insurance">保价服务</label>
                <input type="checkbox" id="express" name="express" value="1">
                <label for="express">加急配送</label>
            </div>
        </div>

        <button type="button" id="calculate">计算运费</button>
    </form>

    <div id="result"></div>

    <script>
        document.getElementById('calculate').addEventListener('click', function() {
            // 模拟计算耗时约1秒
            setTimeout(function() {
                const result = document.getElementById('result');
                result.textContent = '¥45.00';
            }, 1000);
        });
    </script>
</body>
</html>

2.3 测试脚本实现

创建 test_shipping_cost.py 文件:

python 复制代码
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 创建 Edge 浏览器实例
driver = webdriver.Edge()
# 浏览器最大化显示
driver.maximize_window()

# 访问页面(根据任务要求,运费计算文件存放在specified_directory目录中)
driver.get("http://localhost:8000/specified_directory/shipping_calculator.html")

try:
    # 1. 定位寄件重量输入框,清空并输入5
    weight_input = driver.find_element(By.ID, "weight")
    weight_input.clear()
    weight_input.send_keys("5")

    # 2. 定位"易碎品"单选按钮,并选中
    fragile_radio = driver.find_element(By.XPATH, "//input[@value='fragile']")
    fragile_radio.click()

    # 3. 定位"保价服务"复选框,并勾选
    insurance_checkbox = driver.find_element(By.XPATH, "//input[@id='insurance']")
    insurance_checkbox.click()

    # 4. 定位"加急配送"复选框,并勾选
    express_checkbox = driver.find_element(By.XPATH, "//input[@id='express']")
    express_checkbox.click()

    # 5. 定位"计算运费"按钮,并点击
    calculate_button = driver.find_element(By.XPATH, "//button[text()='计算运费']")
    calculate_button.click()

    # 6. 使用显式等待,等待运费结果显示区域加载完成
    wait = WebDriverWait(driver, 10)
    result_element = wait.until(EC.text_to_be_present_in_element((By.XPATH, "//div[contains(@id,'result')]"), "¥"))
    result_element = driver.find_element(By.XPATH, "//div[contains(@id,'result')]")

    # 7. 获取显示的运费金额,预期结果为 ¥45.00,并进行断言验证
    fee_text = result_element.text.strip()
    expected_fee = "¥45.00"
    assert fee_text == expected_fee, f"期望运费为 {expected_fee},但实际为 {fee_text}"
    print("运费计算正确!")

except Exception as e:
    print(f"测试失败:{e}")
finally:
    # 测试完成后等待15秒再关闭浏览器
    time.sleep(15)
    driver.quit()

第3章 在线注册功能测试

3.1 场景说明

用户访问网站注册页面,填写注册信息,提交注册表单,验证注册成功。

3.2 网页实现

创建 online_registration.html 文件:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>在线注册测试</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 600px;
            margin: 0 auto;
            padding: 20px;
        }
        .form-group {
            margin-bottom: 15px;
        }
        label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
        }
        input[type="text"], input[type="email"], input[type="password"] {
            width: 100%;
            padding: 8px;
            box-sizing: border-box;
            border: 1px solid #ddd;
            border-radius: 4px;
        }
        .checkbox-group {
            margin-top: 10px;
        }
        .checkbox-group label {
            display: inline;
            font-weight: normal;
        }
        button {
            background-color: #4CAF50;
            color: white;
            border: none;
            padding: 10px 20px;
            cursor: pointer;
            border-radius: 4px;
            font-size: 16px;
        }
        button:hover {
            background-color: #45a049;
        }
        #captcha-section {
            display: flex;
            gap: 10px;
            align-items: center;
        }
        #captcha-btn {
            background-color: #2196F3;
            padding: 8px 12px;
            font-size: 14px;
        }
        #captcha-btn:hover {
            background-color: #0b7dda;
        }
        #captcha-btn:disabled {
            background-color: #cccccc;
            cursor: not-allowed;
        }
        .message {
            margin: 20px 0;
            padding: 10px;
            border-radius: 4px;
            font-weight: bold;
        }
        .success {
            background-color: #d4edda;
            color: #155724;
            border: 1px solid #c3e6cb;
        }
        .error {
            background-color: #f8d7da;
            color: #721c24;
            border: 1px solid #f5c6cb;
        }
    </style>
</head>
<body>
    <h1>在线注册测试</h1>

    <div id="message" class="message" style="display: none;"></div>

    <form id="registration-form">
        <div class="form-group">
            <label for="username">用户名:</label>
            <input type="text" id="username" name="username" placeholder="请输入用户名" required>
        </div>

        <div class="form-group">
            <label for="email">邮箱:</label>
            <input type="email" id="email" name="email" placeholder="请输入邮箱" required>
        </div>

        <div class="form-group">
            <label for="password">密码:</label>
            <input type="password" id="password" name="password" placeholder="请输入密码" required>
        </div>

        <div class="form-group">
            <label for="confirm-password">确认密码:</label>
            <input type="password" id="confirm-password" name="confirm-password" placeholder="请再次输入密码" required>
        </div>

        <div class="form-group">
            <label for="captcha">验证码:</label>
            <div id="captcha-section">
                <input type="text" id="captcha" name="captcha" placeholder="请输入验证码" required>
                <button type="button" id="captcha-btn">获取验证码</button>
            </div>
        </div>

        <div class="checkbox-group">
            <input type="checkbox" id="agree" name="agree" required>
            <label for="agree">我同意<a href="#">用户协议</a>和<a href="#">隐私政策</a></label>
        </div>

        <button type="submit">注册</button>
    </form>

    <script>
        // 验证码倒计时
        let countdown = 0;
        let timer = null;

        // 验证码按钮点击事件
        document.getElementById('captcha-btn').addEventListener('click', function() {
            const email = document.getElementById('email').value;
            if (!email) {
                showMessage('请先输入邮箱', 'error');
                return;
            }

            // 开始倒计时
            startCountdown(60);
            showMessage('验证码已发送到您的邮箱,验证码为:123456', 'success');
        });

        // 倒计时函数
        function startCountdown(seconds) {
            countdown = seconds;
            const btn = document.getElementById('captcha-btn');
            btn.disabled = true;
            btn.textContent = `${countdown}秒后重新获取`;

            if (timer) {
                clearInterval(timer);
            }

            timer = setInterval(() => {
                countdown--;
                if (countdown <= 0) {
                    clearInterval(timer);
                    btn.disabled = false;
                    btn.textContent = '获取验证码';
                } else {
                    btn.textContent = `${countdown}秒后重新获取`;
                }
            }, 1000);
        }

        // 显示消息
        function showMessage(text, type) {
            const message = document.getElementById('message');
            message.textContent = text;
            message.className = `message ${type}`;
            message.style.display = 'block';
        }

        // 注册表单提交事件
        document.getElementById('registration-form').addEventListener('submit', function(e) {
            e.preventDefault();

            const username = document.getElementById('username').value;
            const email = document.getElementById('email').value;
            const password = document.getElementById('password').value;
            const confirmPassword = document.getElementById('confirm-password').value;
            const captcha = document.getElementById('captcha').value;
            const agree = document.getElementById('agree').checked;

            // 简单验证
            if (!username || !email || !password || !confirmPassword || !captcha || !agree) {
                showMessage('请填写所有必填字段', 'error');
                return;
            }

            if (password !== confirmPassword) {
                showMessage('两次输入的密码不一致', 'error');
                return;
            }

            if (captcha !== '123456') {
                showMessage('验证码错误', 'error');
                return;
            }

            // 模拟注册成功
            setTimeout(() => {
                showMessage('注册成功!', 'success');
                // 清空表单
                this.reset();
            }, 1000);
        });
    </script>
</body>
</html>

3.3 测试脚本实现

创建 test_online_registration.py 文件:

python 复制代码
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 创建 Edge 浏览器实例
driver = webdriver.Edge()
# 浏览器最大化显示
driver.maximize_window()

try:
    # 访问页面
    driver.get("http://localhost:8000/online_registration/online_registration.html")

    # 输入用户名
    username_input = driver.find_element(By.ID, "username")
    username_input.send_keys("testuser123")

    # 输入邮箱
    email_input = driver.find_element(By.ID, "email")
    email_input.send_keys("test@example.com")

    # 输入密码
    password_input = driver.find_element(By.ID, "password")
    password_input.send_keys("Password123!")

    # 输入确认密码
    confirm_password_input = driver.find_element(By.ID, "confirm-password")
    confirm_password_input.send_keys("Password123!")

    # 点击"获取验证码"按钮
    captcha_btn = driver.find_element(By.ID, "captcha-btn")
    captcha_btn.click()

    # 输入验证码
    captcha_input = driver.find_element(By.ID, "captcha")
    captcha_input.send_keys("123456")

    # 勾选"同意用户协议"复选框
    agree_checkbox = driver.find_element(By.ID, "agree")
    agree_checkbox.click()

    # 点击"注册"按钮
    register_btn = driver.find_element(By.XPATH, "//button[text()='注册']")
    register_btn.click()

    # 等待注册成功提示
    success_message = WebDriverWait(driver, 10).until(
        EC.text_to_be_present_in_element((By.ID, "message"), "注册成功")
    )

    # 断言验证
    actual_message = driver.find_element(By.ID, "message").text
    expected_message = "注册成功!"
    assert actual_message == expected_message, f"期望消息为 {expected_message},但实际为 {actual_message}"
    print(f"测试通过!实际消息:{actual_message}")

except Exception as e:
    print(f"测试失败:{e}")
finally:
    # 测试完成后等待15秒再关闭浏览器
    time.sleep(15)
    driver.quit()

第4章 电商购物车测试

4.1 场景说明

用户浏览商品,添加商品到购物车,修改商品数量,选择配送方式,计算总价。

4.2 网页实现

创建 ecommerce_cart.html 文件:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>电商购物车测试</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 1000px;
            margin: 0 auto;
            padding: 20px;
        }
        .product-list {
            display: flex;
            gap: 20px;
            margin-bottom: 30px;
        }
        .product {
            border: 1px solid #ddd;
            padding: 15px;
            width: 200px;
        }
        .cart {
            border: 1px solid #ddd;
            padding: 20px;
            margin-top: 30px;
        }
        .cart-item {
            display: flex;
            justify-content: space-between;
            margin: 10px 0;
            padding: 10px 0;
            border-bottom: 1px solid #eee;
        }
        .quantity-control {
            display: flex;
            align-items: center;
            gap: 10px;
        }
        .shipping-options {
            margin: 20px 0;
        }
        .total {
            font-size: 20px;
            font-weight: bold;
            margin-top: 20px;
        }
        button {
            background-color: #4CAF50;
            color: white;
            border: none;
            padding: 8px 16px;
            cursor: pointer;
        }
        button:hover {
            background-color: #45a049;
        }
    </style>
</head>
<body>
    <h1>电商购物车测试</h1>

    <div class="product-list">
        <div class="product">
            <h3>笔记本电脑</h3>
            <p>价格:¥5000.00</p>
            <button class="add-to-cart" data-name="笔记本电脑" data-price="5000">加入购物车</button>
        </div>
        <div class="product">
            <h3>智能手机</h3>
            <p>价格:¥3000.00</p>
            <button class="add-to-cart" data-name="智能手机" data-price="3000">加入购物车</button>
        </div>
        <div class="product">
            <h3>无线耳机</h3>
            <p>价格:¥500.00</p>
            <button class="add-to-cart" data-name="无线耳机" data-price="500">加入购物车</button>
        </div>
    </div>

    <div class="cart">
        <h2>购物车</h2>
        <div id="cart-items"></div>

        <div class="shipping-options">
            <h3>配送方式:</h3>
            <label>
                <input type="radio" name="shipping" value="standard" checked> 标准配送 (¥0.00)
            </label><br>
            <label>
                <input type="radio" name="shipping" value="express"> 顺丰快递 (¥20.00)
            </label>
        </div>

        <div class="total">
            总价:<span id="total-price">¥0.00</span>
        </div>
    </div>

    <script>
        // 购物车数据
        let cart = [];
        let shippingCost = 0;

        // 添加到购物车
        document.querySelectorAll('.add-to-cart').forEach(button => {
            button.addEventListener('click', function() {
                const name = this.dataset.name;
                const price = parseFloat(this.dataset.price);

                // 检查商品是否已在购物车中
                const existingItem = cart.find(item => item.name === name);
                if (existingItem) {
                    existingItem.quantity += 1;
                } else {
                    cart.push({ name, price, quantity: 1 });
                }

                updateCart();
            });
        });

        // 更新购物车显示
        function updateCart() {
            const cartItems = document.getElementById('cart-items');
            cartItems.innerHTML = '';

            let subtotal = 0;

            cart.forEach(item => {
                const itemElement = document.createElement('div');
                itemElement.className = 'cart-item';

                const itemPrice = item.price * item.quantity;
                subtotal += itemPrice;

                itemElement.innerHTML = `
                    <div>
                        <h4>${item.name}</h4>
                        <p>单价:¥${item.price.toFixed(2)}</p>
                    </div>
                    <div class="quantity-control">
                        <button class="decrease" data-name="${item.name}">-</button>
                        <span>${item.quantity}</span>
                        <button class="increase" data-name="${item.name}">+</button>
                    </div>
                    <div>¥${itemPrice.toFixed(2)}</div>
                `;

                cartItems.appendChild(itemElement);
            });

            // 添加数量控制事件
            addQuantityControls();

            // 计算总价
            const total = subtotal + shippingCost;
            document.getElementById('total-price').textContent = `¥${total.toFixed(2)}`;
        }

        // 添加数量控制事件
        function addQuantityControls() {
            // 减少数量
            document.querySelectorAll('.decrease').forEach(button => {
                button.addEventListener('click', function() {
                    const name = this.dataset.name;
                    const item = cart.find(item => item.name === name);
                    if (item && item.quantity > 1) {
                        item.quantity -= 1;
                        updateCart();
                    }
                });
            });

            // 增加数量
            document.querySelectorAll('.increase').forEach(button => {
                button.addEventListener('click', function() {
                    const name = this.dataset.name;
                    const item = cart.find(item => item.name === name);
                    if (item) {
                        item.quantity += 1;
                        updateCart();
                    }
                });
            });
        }

        // 配送方式选择
        document.querySelectorAll('input[name="shipping"]').forEach(radio => {
            radio.addEventListener('change', function() {
                shippingCost = this.value === 'express' ? 20 : 0;
                updateCart();
            });
        });
    </script>
</body>
</html>

4.3 测试脚本实现

创建 test_ecommerce_cart.py 文件:

python 复制代码
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 创建 Edge 浏览器实例
driver = webdriver.Edge()
# 浏览器最大化显示
driver.maximize_window()

try:
    # 访问页面
    driver.get("http://localhost:8000/ecommerce_cart/ecommerce_cart.html")

    # 点击"笔记本电脑"的"加入购物车"按钮
    laptop_add_button = driver.find_element(By.XPATH, "//h3[text()='笔记本电脑']/following-sibling::button")
    laptop_add_button.click()

    # 点击"增加"按钮将数量从1改为2
    increase_button = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.XPATH, "//div[contains(@class, 'cart-item')]//button[text()='+']"))
    )
    increase_button.click()

    # 选择"顺丰快递"配送方式
    express_shipping = driver.find_element(By.XPATH, "//input[@value='express']")
    express_shipping.click()

    # 等待总价更新
    total_price = WebDriverWait(driver, 10).until(
        EC.text_to_be_present_in_element((By.ID, "total-price"), "¥10020.00")
    )

    # 断言验证
    actual_total = driver.find_element(By.ID, "total-price").text
    expected_total = "¥10020.00"
    assert actual_total == expected_total, f"期望总价为 {expected_total},但实际为 {actual_total}"
    print(f"测试通过!实际总价:{actual_total}")

except Exception as e:
    print(f"测试失败:{e}")
finally:
    # 测试完成后等待15秒再关闭浏览器
    time.sleep(15)
    driver.quit()

第5章 航班查询功能测试

5.1 场景说明

用户访问机票预订网站,输入出发地、目的地、日期,查询航班信息,选择航班查看详情。

5.2 网页实现

创建 flight_search.html 文件:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>航班查询测试</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 1000px;
            margin: 0 auto;
            padding: 20px;
        }
        .search-form {
            background-color: #f0f8ff;
            padding: 20px;
            border-radius: 8px;
            margin-bottom: 30px;
        }
        .form-row {
            display: flex;
            gap: 20px;
            margin-bottom: 15px;
            align-items: center;
        }
        .form-group {
            flex: 1;
        }
        label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
        }
        input, select, button {
            width: 100%;
            padding: 8px;
            box-sizing: border-box;
            border: 1px solid #ddd;
            border-radius: 4px;
        }
        button {
            background-color: #4CAF50;
            color: white;
            border: none;
            cursor: pointer;
            font-size: 16px;
        }
        button:hover {
            background-color: #45a049;
        }
        .trip-type {
            display: flex;
            gap: 10px;
        }
        .trip-type label {
            display: inline;
            font-weight: normal;
        }
        #flight-results {
            margin-top: 20px;
        }
        .flight-item {
            border: 1px solid #ddd;
            padding: 20px;
            margin-bottom: 15px;
            border-radius: 8px;
        }
        .flight-item:hover {
            box-shadow: 0 5px 15px rgba(0,0,0,0.1);
        }
        .flight-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 15px;
        }
        .flight-info {
            display: flex;
            justify-content: space-between;
            margin: 10px 0;
        }
        .flight-time {
            font-size: 24px;
            font-weight: bold;
        }
        .flight-route {
            display: flex;
            align-items: center;
            gap: 10px;
        }
        .flight-duration {
            color: #666;
        }
        .view-details {
            background-color: #2196F3;
            color: white;
            border: none;
            padding: 8px 16px;
            cursor: pointer;
            border-radius: 4px;
            font-size: 14px;
        }
        .view-details:hover {
            background-color: #0b7dda;
        }
        .flight-details {
            margin-top: 15px;
            padding-top: 15px;
            border-top: 1px solid #eee;
            display: none;
        }
        .flight-details.show {
            display: block;
        }
        .message {
            margin: 20px 0;
            padding: 10px;
            border-radius: 4px;
            font-weight: bold;
        }
        .loading {
            background-color: #d1ecf1;
            color: #0c5460;
            border: 1px solid #bee5eb;
        }
    </style>
</head>
<body>
    <h1>航班查询测试</h1>

    <div id="message" class="message" style="display: none;"></div>

    <div class="search-form">
        <h2>航班查询</h2>

        <div class="form-row">
            <div class="trip-type">
                <input type="radio" id="one-way" name="trip-type" value="one-way" checked>
                <label for="one-way">单程</label>
                <input type="radio" id="round-trip" name="trip-type" value="round-trip">
                <label for="round-trip">往返</label>
            </div>
        </div>

        <div class="form-row">
            <div class="form-group">
                <label for="from">出发地:</label>
                <select id="from" name="from">
                    <option value="北京">北京</option>
                    <option value="上海">上海</option>
                    <option value="广州">广州</option>
                    <option value="深圳">深圳</option>
                    <option value="成都">成都</option>
                </select>
            </div>

            <div class="form-group">
                <label for="to">目的地:</label>
                <select id="to" name="to">
                    <option value="北京">北京</option>
                    <option value="上海">上海</option>
                    <option value="广州">广州</option>
                    <option value="深圳">深圳</option>
                    <option value="成都">成都</option>
                </select>
            </div>
        </div>

        <div class="form-row">
            <div class="form-group">
                <label for="departure-date">出发日期:</label>
                <input type="date" id="departure-date" name="departure-date" required>
            </div>

            <div class="form-group" id="return-date-group" style="display: none;">
                <label for="return-date">返回日期:</label>
                <input type="date" id="return-date" name="return-date">
            </div>
        </div>

        <button type="button" id="search-flights">搜索航班</button>
    </div>

    <div id="flight-results"></div>

    <script>
        // 设置默认出发日期为明天
        document.addEventListener('DOMContentLoaded', function() {
            const tomorrow = new Date();
            tomorrow.setDate(tomorrow.getDate() + 1);
            const formattedDate = tomorrow.toISOString().split('T')[0];
            document.getElementById('departure-date').value = formattedDate;
        });

        // 往返/单程切换
        document.querySelectorAll('input[name="trip-type"]').forEach(radio => {
            radio.addEventListener('change', function() {
                const returnDateGroup = document.getElementById('return-date-group');
                if (this.value === 'round-trip') {
                    returnDateGroup.style.display = 'block';
                } else {
                    returnDateGroup.style.display = 'none';
                }
            });
        });

        // 航班数据
        const flightData = [
            {
                id: 1,
                airline: '中国国际航空',
                flightNumber: 'CA1234',
                departureCity: '北京',
                departureTime: '08:00',
                arrivalCity: '上海',
                arrivalTime: '10:30',
                duration: '2小时30分钟',
                price: '¥800.00',
                details: '机型:波音737-800,准点率:95%,行李额:20kg'
            },
            {
                id: 2,
                airline: '东方航空',
                flightNumber: 'MU5678',
                departureCity: '北京',
                departureTime: '10:00',
                arrivalCity: '上海',
                arrivalTime: '12:30',
                duration: '2小时30分钟',
                price: '¥750.00',
                details: '机型:空客A320,准点率:92%,行李额:20kg'
            },
            {
                id: 3,
                airline: '南方航空',
                flightNumber: 'CZ9012',
                departureCity: '北京',
                departureTime: '12:00',
                arrivalCity: '上海',
                arrivalTime: '14:30',
                duration: '2小时30分钟',
                price: '¥780.00',
                details: '机型:波音737-800,准点率:90%,行李额:20kg'
            }
        ];

        // 显示消息
        function showMessage(text, type) {
            const message = document.getElementById('message');
            message.textContent = text;
            message.className = `message ${type}`;
            message.style.display = 'block';
        }

        // 隐藏消息
        function hideMessage() {
            const message = document.getElementById('message');
            message.style.display = 'none';
        }

        // 搜索航班
        document.getElementById('search-flights').addEventListener('click', function() {
            // 显示加载中消息
            showMessage('正在搜索航班...', 'loading');

            // 模拟网络延迟
            setTimeout(() => {
                hideMessage();
                displayFlights();
            }, 1500);
        });

        // 显示航班列表
        function displayFlights() {
            const resultsContainer = document.getElementById('flight-results');
            resultsContainer.innerHTML = '';

            if (flightData.length === 0) {
                resultsContainer.innerHTML = '<p>没有找到符合条件的航班。</p>';
                return;
            }

            flightData.forEach(flight => {
                const flightElement = document.createElement('div');
                flightElement.className = 'flight-item';
                flightElement.innerHTML = `
                    <div class="flight-header">
                        <div>
                            <h3>${flight.airline} ${flight.flightNumber}</h3>
                        </div>
                        <div style="font-size: 20px; font-weight: bold;">${flight.price}</div>
                    </div>

                    <div class="flight-info">
                        <div class="flight-time">${flight.departureTime}</div>
                        <div class="flight-route">
                            <strong>${flight.departureCity}</strong>
                            <span>→</span>
                            <strong>${flight.arrivalCity}</strong>
                        </div>
                        <div class="flight-time">${flight.arrivalTime}</div>
                    </div>

                    <div class="flight-info">
                        <div></div>
                        <div class="flight-duration">${flight.duration}</div>
                        <div></div>
                    </div>

                    <div style="display: flex; justify-content: space-between; align-items: center;">
                        <button class="view-details" onclick="toggleDetails(${flight.id})">查看详情</button>
                    </div>

                    <div id="details-${flight.id}" class="flight-details">
                        <p>${flight.details}</p>
                    </div>
                `;

                resultsContainer.appendChild(flightElement);
            });
        }

        // 切换详情显示
        window.toggleDetails = function(flightId) {
            const detailsElement = document.getElementById(`details-${flightId}`);
            detailsElement.classList.toggle('show');
        }
    </script>
</body>
</html>

5.3 测试脚本实现

创建 test_flight_search.py 文件:

python 复制代码
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 创建 Edge 浏览器实例
driver = webdriver.Edge()
# 浏览器最大化显示
driver.maximize_window()

try:
    # 访问页面
    driver.get("http://localhost:8000/flight_search/flight_search.html")

    # 选择目的地为上海
    to_select = driver.find_element(By.ID, "to")
    to_select.send_keys("上海")

    # 点击"搜索航班"按钮
    search_button = driver.find_element(By.ID, "search-flights")
    search_button.click()

    # 等待航班列表加载
    flight_items = WebDriverWait(driver, 10).until(
        EC.presence_of_all_elements_located((By.XPATH, "//div[@class='flight-item']"))
    )

    # 选择第一个航班,点击"查看详情"
    view_details_button = flight_items[0].find_element(By.XPATH, ".//button[text()='查看详情']")
    view_details_button.click()

    # 等待航班详情显示
    flight_details = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.XPATH, "//div[@class='flight-details show']"))
    )

    # 断言验证
    actual_details = flight_details.text
    expected_keyword = "机型:"
    assert expected_keyword in actual_details, f"期望详情中包含 '{expected_keyword}',但实际为 '{actual_details}'"
    print(f"测试通过!航班详情:{actual_details}")

except Exception as e:
    print(f"测试失败:{e}")
finally:
    # 测试完成后等待15秒再关闭浏览器
    time.sleep(15)
    driver.quit()

第6章 银行转账功能测试

6.1 场景说明

用户登录网上银行,进行账户间转账,输入转账金额,验证转账结果。

6.2 网页实现

创建 bank_transfer.html 文件:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>银行转账测试</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
        }
        .transfer-form {
            background-color: #f0f8ff;
            padding: 20px;
            border-radius: 8px;
            margin-bottom: 30px;
        }
        .form-group {
            margin-bottom: 15px;
        }
        label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
        }
        select, input, button {
            width: 100%;
            padding: 8px;
            box-sizing: border-box;
            border: 1px solid #ddd;
            border-radius: 4px;
        }
        button {
            background-color: #4CAF50;
            color: white;
            border: none;
            cursor: pointer;
            font-size: 16px;
        }
        button:hover {
            background-color: #45a049;
        }
        .message {
            margin: 20px 0;
            padding: 10px;
            border-radius: 4px;
            font-weight: bold;
        }
        .success {
            background-color: #d4edda;
            color: #155724;
            border: 1px solid #c3e6cb;
        }
        .error {
            background-color: #f8d7da;
            color: #721c24;
            border: 1px solid #f5c6cb;
        }
        .loading {
            background-color: #d1ecf1;
            color: #0c5460;
            border: 1px solid #bee5eb;
        }
    </style>
</head>
<body>
    <h1>银行转账测试</h1>

    <div id="message" class="message" style="display: none;"></div>

    <div class="transfer-form">
        <h2>账户转账</h2>

        <div class="form-group">
            <label for="from-account">转出账户:</label>
            <select id="from-account" name="from-account">
                <option value="1234567890">储蓄账户 (尾号:7890) - 余额:¥10,000.00</option>
                <option value="0987654321">活期账户 (尾号:4321) - 余额:¥5,000.00</option>
            </select>
        </div>

        <div class="form-group">
            <label for="to-account">转入账户:</label>
            <select id="to-account" name="to-account">
                <option value="5678901234">张三 (尾号:1234) - 工商银行</option>
                <option value="6789012345">李四 (尾号:2345) - 建设银行</option>
                <option value="7890123456">王五 (尾号:3456) - 农业银行</option>
            </select>
        </div>

        <div class="form-group">
            <label for="amount">转账金额:</label>
            <input type="number" id="amount" name="amount" placeholder="请输入转账金额" min="0.01" step="0.01" required>
        </div>

        <div class="form-group">
            <label for="transaction-password">交易密码:</label>
            <input type="password" id="transaction-password" name="transaction-password" placeholder="请输入交易密码" required>
        </div>

        <button type="button" id="transfer-btn">确认转账</button>
    </div>

    <script>
        // 显示消息
        function showMessage(text, type) {
            const message = document.getElementById('message');
            message.textContent = text;
            message.className = `message ${type}`;
            message.style.display = 'block';
        }

        // 隐藏消息
        function hideMessage() {
            const message = document.getElementById('message');
            message.style.display = 'none';
        }

        // 转账按钮点击事件
        document.getElementById('transfer-btn').addEventListener('click', function() {
            const amount = parseFloat(document.getElementById('amount').value);
            const transactionPassword = document.getElementById('transaction-password').value;

            // 简单验证
            if (isNaN(amount) || amount <= 0) {
                showMessage('请输入有效的转账金额', 'error');
                return;
            }

            if (!transactionPassword) {
                showMessage('请输入交易密码', 'error');
                return;
            }

            if (transactionPassword !== '123456') {
                showMessage('交易密码错误', 'error');
                return;
            }

            // 显示加载中消息
            showMessage('正在处理转账...', 'loading');

            // 模拟网络延迟
            setTimeout(() => {
                hideMessage();

                // 模拟转账成功
                showMessage(`转账成功!转账金额:¥${amount.toFixed(2)}`, 'success');

                // 清空表单
                document.getElementById('amount').value = '';
                document.getElementById('transaction-password').value = '';
            }, 2000);
        });
    </script>
</body>
</html>

6.3 测试脚本实现

创建 test_bank_transfer.py 文件:

python 复制代码
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 创建 Edge 浏览器实例
driver = webdriver.Edge()
# 浏览器最大化显示
driver.maximize_window()

try:
    # 访问页面
    driver.get("http://localhost:8000/bank_transfer/bank_transfer.html")

    # 选择转入账户为李四
    to_account = driver.find_element(By.ID, "to-account")
    to_account.send_keys("李四")

    # 输入转账金额1000
    amount_input = driver.find_element(By.ID, "amount")
    amount_input.send_keys("1000")

    # 输入交易密码123456
    transaction_password = driver.find_element(By.ID, "transaction-password")
    transaction_password.send_keys("123456")

    # 点击"确认转账"按钮
    transfer_button = driver.find_element(By.ID, "transfer-btn")
    transfer_button.click()

    # 等待转账结果提示
    success_message = WebDriverWait(driver, 10).until(
        EC.text_to_be_present_in_element((By.ID, "message"), "转账成功")
    )

    # 断言验证
    actual_message = driver.find_element(By.ID, "message").text
    expected_message = "转账成功!转账金额:¥1000.00"
    assert actual_message == expected_message, f"期望消息为 {expected_message},但实际为 {actual_message}"
    print(f"测试通过!转账结果:{actual_message}")

except Exception as e:
    print(f"测试失败:{e}")
finally:
    # 测试完成后等待15秒再关闭浏览器
    time.sleep(15)
    driver.quit()

第7章 在线教育课程报名测试

7.1 场景说明

用户访问在线教育平台,浏览课程,选择课程,填写报名信息,提交报名。

7.2 网页实现

创建 online_education.html 文件:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>在线教育课程报名测试</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
        }
        .course-list {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
            gap: 20px;
            margin-bottom: 30px;
        }
        .course-item {
            border: 1px solid #ddd;
            padding: 20px;
            border-radius: 8px;
            cursor: pointer;
            transition: transform 0.2s;
        }
        .course-item:hover {
            transform: translateY(-5px);
            box-shadow: 0 5px 15px rgba(0,0,0,0.1);
        }
        .course-item h3 {
            margin-top: 0;
        }
        .course-price {
            font-size: 20px;
            font-weight: bold;
            color: #e74c3c;
            margin: 10px 0;
        }
        .course-details {
            margin-top: 30px;
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 8px;
        }
        .course-details h2 {
            margin-top: 0;
        }
        .course-info {
            display: flex;
            gap: 20px;
            margin: 20px 0;
            color: #666;
        }
        .enrollment-form {
            margin-top: 30px;
            padding: 20px;
            background-color: #f0f8ff;
            border-radius: 8px;
        }
        .form-row {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 20px;
            margin-bottom: 15px;
        }
        .form-group {
            display: flex;
            flex-direction: column;
        }
        label {
            margin-bottom: 5px;
            font-weight: bold;
        }
        input, select, button {
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
        }
        button {
            background-color: #4CAF50;
            color: white;
            border: none;
            padding: 10px 20px;
            cursor: pointer;
            font-size: 16px;
        }
        button:hover {
            background-color: #45a049;
        }
        .payment-options {
            margin: 20px 0;
        }
        .payment-options h4 {
            margin-bottom: 10px;
        }
        .payment-options label {
            display: inline;
            font-weight: normal;
            margin-right: 15px;
        }
        .message {
            margin: 20px 0;
            padding: 10px;
            border-radius: 4px;
            font-weight: bold;
        }
        .success {
            background-color: #d4edda;
            color: #155724;
            border: 1px solid #c3e6cb;
        }
        .error {
            background-color: #f8d7da;
            color: #721c24;
            border: 1px solid #f5c6cb;
        }
        .loading {
            background-color: #d1ecf1;
            color: #0c5460;
            border: 1px solid #bee5eb;
        }
        #message {
            margin-top: 20px;
        }
    </style>
</head>
<body>
    <h1>在线教育课程报名测试</h1>

    <div id="message" class="message" style="display: none;"></div>

    <h2>课程列表</h2>

    <div class="course-list">
        <div class="course-item" data-course="python">
            <h3>Python编程基础</h3>
            <p>适合零基础学员,学习Python编程的基础知识和核心概念。</p>
            <div class="course-price">¥999.00</div>
            <p>课时:40小时 | 讲师:张老师 | 评分:4.8/5.0</p>
        </div>

        <div class="course-item" data-course="java">
            <h3>Java企业开发</h3>
            <p>学习Java企业级应用开发,包括Spring Boot、Spring Cloud等框架。</p>
            <div class="course-price">¥1299.00</div>
            <p>课时:50小时 | 讲师:李老师 | 评分:4.7/5.0</p>
        </div>

        <div class="course-item" data-course="web">
            <h3>Web前端开发</h3>
            <p>学习HTML、CSS、JavaScript等Web前端技术,构建现代Web应用。</p>
            <div class="course-price">¥1199.00</div>
            <p>课时:45小时 | 讲师:王老师 | 评分:4.9/5.0</p>
        </div>
    </div>

    <div id="course-details" class="course-details" style="display: none;">
        <h2 id="course-title">Python编程基础</h2>
        <div class="course-info">
            <div>课时:<span id="course-hours">40小时</span></div>
            <div>讲师:<span id="course-teacher">张老师</span></div>
            <div>评分:<span id="course-rating">4.8/5.0</span></div>
        </div>
        <div class="course-price" id="course-price">¥999.00</div>

        <div class="enrollment-form">
            <h3>课程报名</h3>
            <form id="enrollment-form">
                <div class="form-row">
                    <div class="form-group">
                        <label for="student-name">姓名:</label>
                        <input type="text" id="student-name" name="student-name" placeholder="请输入姓名" required>
                    </div>

                    <div class="form-group">
                        <label for="student-phone">电话:</label>
                        <input type="tel" id="student-phone" name="student-phone" placeholder="请输入电话" required>
                    </div>

                    <div class="form-group">
                        <label for="student-email">邮箱:</label>
                        <input type="email" id="student-email" name="student-email" placeholder="请输入邮箱" required>
                    </div>
                </div>

                <div class="payment-options">
                    <h4>支付方式:</h4>
                    <label>
                        <input type="radio" name="payment-method" value="alipay" checked> 支付宝
                    </label>
                    <label>
                        <input type="radio" name="payment-method" value="wechat"> 微信支付
                    </label>
                    <label>
                        <input type="radio" name="payment-method" value="card"> 银行卡
                    </label>
                </div>

                <button type="submit">提交报名</button>
            </form>
        </div>
    </div>

    <script>
        // 课程数据
        const courseData = {
            python: {
                title: 'Python编程基础',
                hours: '40小时',
                teacher: '张老师',
                rating: '4.8/5.0',
                price: '¥999.00'
            },
            java: {
                title: 'Java企业开发',
                hours: '50小时',
                teacher: '李老师',
                rating: '4.7/5.0',
                price: '¥1299.00'
            },
            web: {
                title: 'Web前端开发',
                hours: '45小时',
                teacher: '王老师',
                rating: '4.9/5.0',
                price: '¥1199.00'
            }
        };

        // 显示消息
        function showMessage(text, type) {
            const message = document.getElementById('message');
            message.textContent = text;
            message.className = `message ${type}`;
            message.style.display = 'block';
        }

        // 隐藏消息
        function hideMessage() {
            const message = document.getElementById('message');
            message.style.display = 'none';
        }

        // 选择课程
        document.querySelectorAll('.course-item').forEach(item => {
            item.addEventListener('click', function() {
                const courseKey = this.dataset.course;
                const course = courseData[courseKey];

                // 更新课程详情
                document.getElementById('course-title').textContent = course.title;
                document.getElementById('course-hours').textContent = course.hours;
                document.getElementById('course-teacher').textContent = course.teacher;
                document.getElementById('course-rating').textContent = course.rating;
                document.getElementById('course-price').textContent = course.price;

                // 显示课程详情
                document.getElementById('course-details').style.display = 'block';
            });
        });

        // 提交报名
        document.getElementById('enrollment-form').addEventListener('submit', function(e) {
            e.preventDefault();

            const studentName = document.getElementById('student-name').value;
            const studentPhone = document.getElementById('student-phone').value;
            const studentEmail = document.getElementById('student-email').value;

            // 简单验证
            if (!studentName || !studentPhone || !studentEmail) {
                showMessage('请填写所有必填字段', 'error');
                return;
            }

            // 显示加载中消息
            showMessage('正在处理报名...', 'loading');

            // 模拟网络延迟
            setTimeout(() => {
                hideMessage();
                showMessage('报名成功!我们将尽快与您联系。', 'success');
                // 清空表单
                this.reset();
            }, 1500);
        });
    </script>
</body>
</html>

7.3 测试脚本实现

创建 test_online_education.py 文件:

python 复制代码
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 创建 Edge 浏览器实例
driver = webdriver.Edge()
# 浏览器最大化显示
driver.maximize_window()

try:
    # 访问页面
    driver.get("http://localhost:8000/online_education/online_education.html")

    # 点击"Python编程基础"课程
    python_course = driver.find_element(By.XPATH, "//h3[text()='Python编程基础']/ancestor::div[@class='course-item']")
    python_course.click()

    # 等待课程详情显示
    course_details = WebDriverWait(driver, 10).until(
        EC.visibility_of_element_located((By.ID, "course-details"))
    )

    # 输入姓名
    student_name = driver.find_element(By.ID, "student-name")
    student_name.send_keys("张三")

    # 输入电话
    student_phone = driver.find_element(By.ID, "student-phone")
    student_phone.send_keys("13800138000")

    # 输入邮箱
    student_email = driver.find_element(By.ID, "student-email")
    student_email.send_keys("zhangsan@example.com")

    # 选择微信支付
    wechat_payment = driver.find_element(By.XPATH, "//input[@value='wechat']")
    wechat_payment.click()

    # 点击"提交报名"按钮
    submit_button = driver.find_element(By.XPATH, "//button[text()='提交报名']")
    submit_button.click()

    # 等待报名成功提示
    success_message = WebDriverWait(driver, 10).until(
        EC.text_to_be_present_in_element((By.ID, "message"), "报名成功")
    )

    # 断言验证
    actual_message = driver.find_element(By.ID, "message").text
    expected_message = "报名成功!我们将尽快与您联系。"
    assert actual_message == expected_message, f"期望消息为 {expected_message},但实际为 {actual_message}"
    print(f"测试通过!报名结果:{actual_message}")

except Exception as e:
    print(f"测试失败:{e}")
finally:
    # 测试完成后等待15秒再关闭浏览器
    time.sleep(15)
    driver.quit()

第8章 Selenium 自动化测试最佳实践

8.1 代码组织与结构

  • 模块化设计:将测试代码按照功能或业务模块进行拆分,提高代码复用性和可维护性
  • 页面对象模型(POM):将页面元素和操作封装为页面对象,减少代码重复,提高测试的可维护性
  • 测试数据分离:将测试数据与测试代码分离,便于测试数据的管理和维护

8.2 等待策略

  • 显式等待 :优先使用 WebDriverWait 结合 expected_conditions 等待元素,避免硬编码等待时间
  • 隐式等待:设置适当的隐式等待时间,作为备选方案
  • 避免使用 Thread.sleep():除非特殊情况,否则不建议使用硬编码的等待时间

8.3 元素定位策略

  • 优先使用 ID:ID 是最稳定的定位方式,优先使用
  • 其次使用 XPath:XPath 定位灵活,但要注意避免使用过于复杂或不稳定的 XPath
  • CSS 选择器:对于复杂的元素定位,可以使用 CSS 选择器
  • 避免使用链接文本:链接文本可能会频繁变化,影响测试的稳定性

8.4 测试用例设计

  • 单一职责原则:每个测试用例只测试一个功能点
  • 测试用例独立:测试用例之间应该相互独立,不依赖于其他测试用例的执行结果
  • 正向测试与反向测试结合:既要测试正常流程,也要测试异常情况
  • 测试数据多样化:使用不同的测试数据覆盖各种场景

8.5 错误处理与日志

  • 捕获异常:使用 try-except 块捕获并处理异常,避免测试因单个错误而完全失败
  • 添加日志:在关键步骤添加日志,便于调试和分析测试结果
  • 截图功能:在测试失败时自动截图,便于问题定位

8.6 测试执行与报告

  • 批量执行:使用测试框架(如 pytest)批量执行测试用例
  • 生成报告:生成详细的测试报告,包括测试结果、执行时间、失败原因等
  • 持续集成:将自动化测试集成到 CI/CD 流程中,实现持续测试

8.7 性能与稳定性

  • 避免不必要的操作:减少测试中的不必要操作,提高测试执行效率
  • 合理设置等待时间:根据页面加载情况设置合理的等待时间,避免测试不稳定
  • 资源清理:在测试完成后清理资源,如关闭浏览器、删除临时文件等

第9章 结论

通过本教程,我们学习了如何使用 Selenium 进行自动化测试,包括:

  1. 环境搭建:创建虚拟环境,安装依赖,配置浏览器驱动
  2. 基础操作:元素定位、点击、输入、等待等基本操作
  3. 测试场景
    • 运费计算功能测试
    • 在线注册功能测试
    • 电商购物车测试
    • 航班查询功能测试
    • 银行转账功能测试
    • 在线教育课程报名测试
  4. 最佳实践:代码组织、等待策略、元素定位、测试用例设计等

自动化测试可以提高测试效率,减少人工测试的工作量,确保软件质量。在实际项目中,我们需要根据项目特点和需求,选择合适的测试框架和工具,设计合理的测试用例,编写高质量的测试代码。

希望本教程对你有所帮助,祝你在自动化测试的道路上越走越远!

附录:常见问题与解决方案

Q1:浏览器驱动无法下载

解决方案

  • 检查网络连接是否正常
  • 手动下载对应版本的浏览器驱动,放在系统 PATH 目录下
  • 使用系统已安装的浏览器驱动

Q2:元素定位失败

解决方案

  • 检查元素定位表达式是否正确
  • 确认元素是否在 iframe 中
  • 确认元素是否为动态生成的
  • 使用显式等待等待元素加载完成

Q3:测试执行不稳定

解决方案

  • 增加合理的等待时间
  • 避免使用 Thread.sleep(),使用显式等待
  • 确保测试用例之间相互独立
  • 减少测试中的不必要操作

Q4:浏览器无法打开

解决方案

  • 检查浏览器是否已安装
  • 确认浏览器驱动版本与浏览器版本匹配
  • 检查系统 PATH 是否包含浏览器驱动路径

Q5:测试报告不美观

解决方案

  • 使用 pytest-html 等插件生成美观的 HTML 报告
  • 配置报告样式,添加必要的信息
  • 集成到持续集成工具中,如 Jenkins、GitLab CI 等
相关推荐
食咗未2 小时前
Linux SSH工具的使用
linux·网络·测试工具·ssh·远程登陆
深蓝电商API3 小时前
Scrapy爬取Ajax动态加载页面三种实用方法
爬虫·python·scrapy·ajax
cnxy18815 小时前
Python爬虫进阶:反爬虫策略与Selenium自动化完整指南
爬虫·python·selenium
深蓝电商API17 小时前
Scrapy管道Pipeline深度解析:多方式数据持久化
爬虫·python·scrapy
噎住佩奇17 小时前
(Win11系统)搭建Python爬虫环境
爬虫·python
qq_3363139317 小时前
java基础-IO流(网络爬虫/工具包生成假数据)
java·爬虫·php
阿蔹18 小时前
Session与Cookies
selenium·测试
Wpa.wk19 小时前
性能测试工具 - JMeter工具组件介绍二
运维·经验分享·测试工具·jmeter·自动化·json