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 小时前
052-滑块验证码:丰巢登录
爬虫·js逆向·滑块验证码·aes加密
释槐鸟~2 小时前
还不知道RIDE工具怎么装吗
测试工具·自动化
东鹏特饮4 小时前
A 股创历史新低筛选器phthon爬虫脚本
爬虫·股票·phthon
有技巧搬砖19 小时前
为什么锂电池组的电池老化测试很重要?
测试工具·锂电池·电池老化
蒲公英内测分发1 天前
智能手表卖出去后,包装、说明书和官网里的 App 下载入口怎么统一?
前端·人工智能·测试工具·智能家居·智能硬件·智能手表
蒲公英内测分发1 天前
智能手环出海测试,海外合作方分散在不同国家,Android 测试包怎么持续分发和更新?
android·前端·人工智能·测试工具·智能手表
无语的小歪歪1 天前
ATF 智测 1.0
python·测试工具·集成测试
SHENGWEI胜为2 天前
交换机端口显示正常,终端却获取不到 IP 地址?从 DHCP 流程定位故障
服务器·网络·测试工具·缓存·通信工程
xie881018022 天前
长表格跨页重复表头:排版上的做法
测试工具
老孟说禅2 天前
测试工具示波器的使用
测试工具