俞秋荣 发表于 2025-10-17 17:25:18

自动化测试入门:从零开始搭建你的第一个WebUI项目

<h2 data-pm-slice="0 0 []">为什么要做自动化测试?</h2>
<p>在深入技术细节前,我们先了解自动化测试的价值。手动测试虽然直观,但存在明显局限性:重复劳动、容易出错、耗时耗力且无法快速反馈。而自动化测试恰能弥补这些不足:</p>
<ul >
<li>
<p><strong>提升测试效率</strong>:自动化脚本可以24小时不间断执行</p>
</li>
<li>
<p><strong>提高测试准确性</strong>:避免人为疏忽导致的错误</p>
</li>
<li>
<p><strong>增强测试覆盖</strong>:可轻松执行数千个测试用例</p>
</li>
<li>
<p><strong>快速反馈</strong>:问题及早发现,降低修复成本</p>
</li>
<li>
<p><strong>回归测试利器</strong>:每次代码变更后快速验证现有功能</p>
</li>
</ul>
<p>虽然自动化测试有诸多优势,但并非所有场景都适合自动化。UI频繁变更、一次性功能、主观体验测试等还是更适合手动测试。</p>
<h2>自动化测试技术选型</h2>
<p>WebUI自动化测试领域有多种工具可选,主流选择包括:</p>
<ul >
<li>
<p><strong>Selenium</strong>:最老牌、应用最广泛的Web自动化工具,支持多语言和多浏览器</p>
</li>
<li>
<p><strong>Cypress</strong>:新兴的测试框架,以其强大的调试能力和执行速度著称</p>
</li>
<li>
<p><strong>Puppeteer</strong>:由Google开发,主要用于Chrome浏览器自动化</p>
</li>
<li>
<p><strong>Playwright</strong>:微软推出的测试工具,支持多浏览器且功能强大</p>
</li>
</ul>
<p>对于初学者,<strong>Selenium</strong>是最佳起点,因为它生态成熟、资料丰富,且是许多公司实际使用的技术。</p>
<h2>环境搭建与工具准备</h2>
<p>下面我们开始搭建Selenium自动化测试环境。</p>
<h3>1. 安装编程语言环境</h3>
<p>Selenium支持多种编程语言,这里我们选择Python,因为它语法简洁、上手快速。</p>
<p>访问Python官网下载并安装最新版本。安装时记得勾选"Add Python to PATH"选项。</p>
<p>安装完成后,打开终端/命令提示符,验证安装是否成功:</p>
python --versionpip --version
<h3 data-pm-slice="0 0 []">2. 安装Selenium库</h3>
<p>通过pip安装Selenium包:</p>
pip install selenium
<h3 data-pm-slice="0 0 []">3. 下载浏览器驱动</h3>
<p>Selenium需要通过浏览器驱动来控制浏览器。这里以Chrome为例:</p>
<ul >
<li>
<p>查看Chrome浏览器版本:点击Chrome菜单 → 帮助 → 关于Google Chrome</p>
</li>
<li>
<p>访问ChromeDriver下载页面</p>
</li>
<li>
<p>下载与你的Chrome版本匹配的ChromeDriver</p>
</li>
<li>
<p>将解压后的chromedriver.exe放在合适位置(建议放在项目目录或系统PATH包含的目录)</p>
</li>
</ul>
<h3>4. 选择开发工具</h3>
<p>推荐使用以下任一IDE:</p>
<ul >
<li>
<p><strong>PyCharm</strong>:功能强大的Python专用IDE</p>
</li>
<li>
<p><strong>VS Code</strong>:轻量级且扩展丰富</p>
</li>
<li>
<p><strong>Jupyter Notebook</strong>:适合交互式学习和调试</p>
</li>
</ul>
<h2 data-pm-slice="0 0 []">第一个Selenium脚本</h2>
<p>环境准备就绪后,让我们编写第一个自动化脚本。</p>
<h3>基础脚本示例</h3>
from selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.chrome.service import Serviceimport time# 设置ChromeDriver路径driver_path = "./chromedriver"  # 根据实际情况调整路径# 创建浏览器驱动实例service = Service(executable_path=driver_path)driver = webdriver.Chrome(service=service)try:    # 打开网页    driver.get("https://www.baidu.com")
    # 打印页面标题    print("页面标题:", driver.title)
    # 查找搜索框并输入关键词    search_box = driver.find_element(By.ID, "kw")    search_box.send_keys("自动化测试")
    # 查找搜索按钮并点击    search_btn = driver.find_element(By.ID, "su")    search_btn.click()
    # 等待结果加载    time.sleep(3)
    # 打印新页面标题    print("搜索后页面标题:", driver.title)
finally:    # 关闭浏览器    driver.quit()
<h3 data-pm-slice="0 0 []">脚本解析</h3>
<olstart="1">
<li>
<p><strong>导入模块</strong>:引入必要的Selenium组件</p>
</li>
<li>
<p><strong>配置驱动</strong>:指定ChromeDriver路径</p>
</li>
<li>
<p><strong>初始化驱动</strong>:创建浏览器实例</p>
</li>
<li>
<p><strong>打开网页</strong>:使用get方法导航至目标URL</p>
</li>
<li>
<p><strong>定位元素</strong>:通过ID定位搜索框和按钮</p>
</li>
<li>
<p><strong>执行操作</strong>:在搜索框输入文本并点击按钮</p>
</li>
<li>
<p><strong>清理资源</strong>:关闭浏览器释放资源</p>
</li>
</ol>
<p>运行此脚本,你将看到自动打开Chrome浏览器、访问百度、执行搜索并关闭浏览器的完整过程。</p>
<h2 data-pm-slice="0 0 []">元素定位策略</h2>
<p>元素定位是Web自动化测试的核心。Selenium提供多种定位策略:</p>
<h3>1. ID定位</h3>
<p>最可靠且高效的定位方式,前提是元素有唯一ID。</p>
element = driver.find_element(By.ID, "username")
<h3 data-pm-slice="0 0 []">2. Name定位</h3>
<p>通过name属性定位</p>
element = driver.find_element(By.NAME, "password")
<h3 data-pm-slice="0 0 []">3. XPath定位</h3>
<p>功能强大的定位方式,可通过元素路径、属性等定位。</p>
# 绝对路径(脆弱,不推荐)element = driver.find_element(By.XPATH, "/html/body/div/form/input")# 相对路径(更健壮)element = driver.find_element(By.XPATH, "//input[@placeholder='请输入用户名']")# 包含文本element = driver.find_element(By.XPATH, "//button")
<h3 data-pm-slice="0 0 []">4. CSS选择器定位</h3>
<p>语法简洁,性能优于XPath。</p>
# 通过class定位element = driver.find_element(By.CSS_SELECTOR, ".submit-btn")# 通过属性定位element = driver.find_element(By.CSS_SELECTOR, "input")# 层级组合element = driver.find_element(By.CSS_SELECTOR, "div.form-group > input")
<h3 data-pm-slice="0 0 []">5. 链接文本定位</h3>
<p>专门用于定位超链接。</p>
# 完整文本匹配element = driver.find_element(By.LINK_TEXT, "忘记密码?")# 部分文本匹配element = driver.find_element(By.PARTIAL_LINK_TEXT, "忘记")
<h3 data-pm-slice="0 0 []">6. 类名定位</h3>
<p>通过class属性定位。</p>
element = driver.find_element(By.CLASS_NAME, "btn-primary")
<h3 data-pm-slice="0 0 []">7. 标签名定位</h3>
<p>通过HTML标签名定位。</p>
element = driver.find_element(By.TAG_NAME, "h1")
<p data-pm-slice="0 0 []">定位策略优先级建议:ID > Name > CSS选择器 > XPath > 其他。优先使用稳定且唯一的标识符。</p>
<h2>常用浏览器操作</h2>
<p>掌握元素定位后,我们来看常用的浏览器操作:</p>
<h3>窗口管理</h3>
# 获取当前窗口句柄current_window = driver.current_window_handle# 获取所有窗口句柄all_windows = driver.window_handles# 切换窗口driver.switch_to.window(all_windows)# 最大化窗口driver.maximize_window()# 设置窗口尺寸driver.set_window_size(1200, 800)# 前进/后退driver.forward()driver.back()# 刷新页面driver.refresh()
<h3 data-pm-slice="0 0 []">表单操作</h3>
# 输入文本search_input = driver.find_element(By.ID, "search")search_input.send_keys("测试数据")# 清空输入框search_input.clear()# 单选按钮/复选框checkbox = driver.find_element(By.ID, "agree")checkbox.click()  # 选择checkbox.click()  # 取消选择# 下拉选择框from selenium.webdriver.support.ui import Selectdropdown = Select(driver.find_element(By.ID, "city"))dropdown.select_by_visible_text("北京")  # 按文本选择dropdown.select_by_value("beijing")     # 按值选择dropdown.select_by_index(1)             # 按索引选择
<h3 data-pm-slice="0 0 []">鼠标和键盘操作</h3>
from selenium.webdriver.common.action_chains import ActionChainsfrom selenium.webdriver.common.keys import Keys# 鼠标悬停element = driver.find_element(By.ID, "menu")action = ActionChains(driver)action.move_to_element(element).perform()# 双击action.double_click(element).perform()# 拖放source = driver.find_element(By.ID, "source")target = driver.find_element(By.ID, "target")action.drag_and_drop(source, target).perform()# 键盘操作search_input = driver.find_element(By.ID, "search")search_input.send_keys("自动化测试")search_input.send_keys(Keys.ENTER)  # 按回车键
<h2 data-pm-slice="0 0 []">等待机制</h2>
<p>动态加载内容是现代Web应用的常见特性,因此等待机制对自动化测试至关重要。</p>
<h3>1. 强制等待(不推荐)</h3>
import timetime.sleep(5)  # 无条件等待5秒
<p data-pm-slice="0 0 []">缺点:固定等待时间,无论页面是否加载完成。</p>
<h3>2. 隐式等待</h3>
<p>设置全局等待时间,在查找元素时如未立即找到会轮询等待。</p>
driver.implicitly_wait(10)  # 设置隐式等待10秒
<p data-pm-slice="0 0 []">缺点:只能用于元素查找,不能处理其他条件。</p>
<h3>3. 显式等待(推荐)</h3>
<p>针对特定条件等待,更加灵活智能。</p>
from selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as EC# 等待元素可点击element = WebDriverWait(driver, 10).until(    EC.element_to_be_clickable((By.ID, "submit-btn")))# 等待元素可见element = WebDriverWait(driver, 10).until(    EC.visibility_of_element_located((By.ID, "result")))# 等待元素存在(不一定可见)element = WebDriverWait(driver, 10).until(    EC.presence_of_element_located((By.ID, "dynamic-content")))# 等待文本出现在元素中element = WebDriverWait(driver, 10).until(    EC.text_to_be_present_in_element((By.ID, "status"), "成功"))
<p data-pm-slice="0 0 []">常用预期条件:</p>
<ul >
<li>
<p><code>element_to_be_clickable</code>:元素可点击</p>
</li>
<li>
<p><code>visibility_of_element_located</code>:元素可见</p>
</li>
<li>
<p><code>presence_of_element_located</code>:元素存在于DOM</p>
</li>
<li>
<p><code>text_to_be_present_in_element</code>:元素包含特定文本</p>
</li>
<li>
<p><code>title_contains</code>:页面标题包含特定文本</p>
</li>
<li>
<p><code>alert_is_present</code>:出现警告框</p>
</li>
</ul>
<h2>第一个完整的测试用例</h2>
<p>现在我们综合运用以上知识,创建一个完整的测试用例:</p>
from selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECfrom selenium.webdriver.chrome.service import Serviceimport unittestimport timeclass BaiduSearchTest(unittest.TestCase):
    def setUp(self):        """测试前置条件"""        self.driver_path = "./chromedriver"        self.service = Service(executable_path=self.driver_path)        self.driver = webdriver.Chrome(service=self.service)        self.driver.maximize_window()        self.wait = WebDriverWait(self.driver, 10)
    def tearDown(self):        """测试清理"""        if self.driver:            self.driver.quit()
    def test_search_functionality(self):        """测试百度搜索功能"""        driver = self.driver        wait = self.wait
        # 打开百度首页        driver.get("https://www.baidu.com")
        # 验证页面标题        self.assertIn("百度一下", driver.title)
        # 定位搜索框并输入关键词        search_input = wait.until(            EC.presence_of_element_located((By.ID, "kw"))        )        search_input.send_keys("Selenium自动化测试")
        # 点击搜索按钮        search_btn = driver.find_element(By.ID, "su")        search_btn.click()
        # 等待搜索结果加载        results = wait.until(            EC.presence_of_element_located((By.ID, "content_left"))        )
        # 验证搜索结果页面标题        self.assertIn("Selenium自动化测试", driver.title)
        # 验证搜索结果包含预期内容        self.assertIn("selenium", driver.page_source.lower())if __name__ == "__main__":    unittest.main()
<p data-pm-slice="0 0 []">这个测试用例使用了Python的unittest框架,包含了标准的测试结构:</p>
<ul >
<li>
<p><code>setUp</code>:测试前的准备工作</p>
</li>
<li>
<p><code>test_*</code>:具体的测试方法</p>
</li>
<li>
<p><code>tearDown</code>:测试后的清理工作</p>
</li>
</ul>
<h2 data-pm-slice="0 0 []">测试框架搭建</h2>
<p>单个测试脚本难以应对复杂项目,我们需要建立测试框架来更好地组织和管理测试。</p>
<h3>项目目录结构</h3>
automation_framework/├── config/│   ├── __init__.py│   └── config.py          # 配置文件├── pages/                 # 页面对象模型│   ├── __init__.py│   ├── base_page.py      # 基础页面类│   ├── home_page.py      # 首页│   └── search_page.py    # 搜索结果页├── tests/                # 测试用例│   ├── __init__.py│   ├── test_search.py│   └── test_login.py├── utils/               # 工具类│   ├── __init__.py│   └── helper.py├── reports/             # 测试报告├── logs/               # 日志文件└── requirements.txt    # 依赖列表
<h3 data-pm-slice="0 0 []">页面对象模式(Page Object Model)</h3>
<p>页面对象模式是自动化测试的最佳实践,它将页面封装成对象,提高代码复用性和可维护性。</p>
<p><strong>base_page.py</strong> - 基础页面类:</p>
from selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECclass BasePage:    def __init__(self, driver):        self.driver = driver        self.wait = WebDriverWait(driver, 10)
    def find_element(self, by, value):        return self.wait.until(EC.presence_of_element_located((by, value)))
    def find_clickable_element(self, by, value):        return self.wait.until(EC.element_to_be_clickable((by, value)))
    def click(self, by, value):        element = self.find_clickable_element(by, value)        element.click()
    def input_text(self, by, value, text):        element = self.find_element(by, value)        element.clear()        element.send_keys(text)
<strong data-pm-slice="0 0 []">home_page.py</strong> - 首页封装:
from selenium.webdriver.common.by import Byfrom .base_page import BasePageclass HomePage(BasePage):    # 元素定位器    SEARCH_INPUT = (By.ID, "kw")    SEARCH_BUTTON = (By.ID, "su")
    def __init__(self, driver):        super().__init__(driver)        self.url = "https://www.baidu.com"
    def open(self):        self.driver.get(self.url)        return self
    def search(self, keyword):        self.input_text(*self.SEARCH_INPUT, keyword)        self.click(*self.SEARCH_BUTTON)        return SearchPage(self.driver)
<strong data-pm-slice="0 0 []">search_page.py</strong> - 搜索结果页封装:
from selenium.webdriver.common.by import Byfrom .base_page import BasePageclass SearchPage(BasePage):    RESULTS = (By.ID, "content_left")
    def get_results_count(self):        results = self.find_element(*self.RESULTS)        return len(results.find_elements(By.TAG_NAME, "div"))
    def is_results_displayed(self):        try:            return self.find_element(*self.RESULTS).is_displayed()        except:            return False
<h3 data-pm-slice="0 0 []">配置文件</h3>
<p><strong>config.py</strong> - 统一配置管理:</p>
class Config:    # 浏览器配置    BROWSER = "chrome"    CHROME_DRIVER_PATH = "./chromedriver"    IMPLICIT_WAIT = 10    EXPLICIT_WAIT = 10
    # 测试环境    BASE_URL = "https://www.baidu.com"
    # 测试数据    TEST_SEARCH_KEYWORD = "自动化测试"
<h3 data-pm-slice="0 0 []">改进的测试用例</h3>
<p>使用页面对象模式重构测试用例:</p>
import unittestfrom selenium import webdriverfrom selenium.webdriver.chrome.service import Servicefrom config.config import Configfrom pages.home_page import HomePageclass TestBaiduSearch(unittest.TestCase):
    def setUp(self):        config = Config()        service = Service(executable_path=config.CHROME_DRIVER_PATH)        self.driver = webdriver.Chrome(service=service)        self.driver.implicitly_wait(config.IMPLICIT_WAIT)        self.driver.maximize_window()
    def tearDown(self):        if self.driver:            self.driver.quit()
    def test_search_functionality(self):        """使用页面对象模式测试搜索功能"""        home_page = HomePage(self.driver)        search_page = home_page.open().search("自动化测试")
        # 验证搜索结果        self.assertTrue(search_page.is_results_displayed())        self.assertGreater(search_page.get_results_count(), 0)if __name__ == "__main__":    unittest.main()
<h2 data-pm-slice="0 0 []">高级技巧与最佳实践</h2>
<h3>1. 数据驱动测试</h3>
<p>使用参数化减少代码重复:</p>
import unittestfrom ddt import ddt, data, unpack
@ddtclass DataDrivenTest(unittest.TestCase):
    @data(("Python", 10), ("Java", 8), ("自动化测试", 5))    @unpack    def test_search_different_keywords(self, keyword, min_results):        # 测试逻辑        home_page = HomePage(self.driver)        search_page = home_page.open().search(keyword)
        results_count = search_page.get_results_count()        self.assertGreaterEqual(results_count, min_results)
<h3 data-pm-slice="0 0 []">2. 失败截图</h3>
<p>测试失败时自动截图:</p>
def tearDown(self):    if hasattr(self, '_outcome') and self._outcome.errors:        # 测试失败        screenshot_path = f"screenshots/failure_{self.id()}.png"        self.driver.save_screenshot(screenshot_path)        print(f"测试失败,截图已保存至: {screenshot_path}")
    if self.driver:        self.driver.quit()
<h3 data-pm-slice="0 0 []">3. 日志记录</h3>
<p>添加详细日志帮助调试:</p>
import logging
# 配置日志logging.basicConfig(    level=logging.INFO,    format='%(asctime)s - %(levelname)s - %(message)s',    handlers=[        logging.FileHandler("logs/automation.log"),        logging.StreamHandler()    ])
logger = logging.getLogger(__name__)
# 在测试中使用日志logger.info("开始执行测试: %s", self.id())logger.debug("搜索关键词: %s", keyword)logger.error("测试失败: %s", str(e))
<h3 data-pm-slice="0 0 []">4. 测试报告</h3>
<p>使用HTMLTestRunner生成美观的测试报告:</p>
import HTMLTestRunnerimport unittestimport os
# 发现测试用例test_dir = "./tests"discover = unittest.defaultTestLoader.discover(test_dir, pattern="test_*.py")
# 生成报告report_path = "./reports/test_report.html"with open(report_path, "wb") as f:    runner = HTMLTestRunner.HTMLTestRunner(        stream=f,        title="自动化测试报告",        description="测试结果详情"    )    runner.run(discover)
<h2 data-pm-slice="0 0 []">常见问题与解决方案</h2>
<h3>1. 元素定位失败</h3>
<ul >
<li>
<p><strong>原因</strong>:元素未加载、iframe嵌套、动态ID等</p>
</li>
<li>
<p><strong>解决方案</strong>:</p>
</li>
<ul >
<li>
<p>增加等待时间</p>
</li>
<li>
<p>使用更稳定的定位策略</p>
</li>
<li>
<p>处理iframe:<code>driver.switch_to.frame("frame_name")</code></p>
</li>
</ul>
</ul>
<h3>2. 浏览器兼容性问题</h3>
<ul >
<li>
<p><strong>解决方案</strong>:</p>
</li>
<ul >
<li>
<p>使用WebDriver管理器自动下载匹配的驱动</p>
</li>
<li>
<p>跨浏览器测试:分别配置不同浏览器的驱动</p>
</li>
</ul>
</ul>
<h3>3. 执行速度慢</h3>
<ul >
<li>
<p><strong>优化方法</strong>:</p>
</li>
<ul >
<li>
<p>减少不必要的等待</p>
</li>
<li>
<p>使用headless模式(无界面)</p>
</li>
<li>
<p>并行执行测试用例</p>
</li>
</ul>
</ul>
<h3>4. 测试稳定性差</h3>
<ul >
<li>
<p><strong>改进措施</strong>:</p>
</li>
<ul >
<li>
<p>增加重试机制</p>
</li>
<li>
<p>使用更可靠的定位方式</p>
</li>
<li>
<p>定期维护测试用例</p>
</li>
</ul>
</ul>
<h2>持续学习路径</h2>
<p>掌握了基础WebUI自动化测试后,你可以继续深入学习:</p>
<olstart="1">
<li>
<p><strong>移动端自动化</strong>:Appium框架</p>
</li>
<li>
<p><strong>API测试</strong>:Requests + Pytest</p>
</li>
<li>
<p><strong>性能测试</strong>:JMeter、LoadRunner</p>
</li>
<li>
<p><strong>测试框架进阶</strong>:Pytest、Robot Framework</p>
</li>
<li>
<p><strong>持续集成</strong>:Jenkins、GitLab CI集成自动化测试</p>
</li>
<li>
<p><strong>容器化</strong>:Docker运行测试环境</p>
</li>
</ol>
<h2>结语</h2>
<p>自动化测试是一门既需要技术能力,又需要测试思维的综合技能。通过本文,你已经了解了从环境搭建到框架设计的完整流程。记住,<strong>实践是最好的老师</strong>——从简单的测试用例开始,逐步构建复杂的测试场景,不断优化和改进你的测试框架。</p>
<p>自动化测试不是一蹴而就的,需要持续的学习和实践。希望这篇文章能为你的自动化测试之旅奠定坚实基础,助你在质量保障的道路上越走越远!</p>
<p data-pid="SWSWY0PQ">本文原创于【程序员二黑】公众号,转载请注明出处!</p>
<p data-pid="g6rZbMxO">欢迎大家关注笔者的公众号:程序员二黑,专注于软件测试干活分享,全套测试资源可免费分享!</p>
<p data-pid="hrpfxYS7">最后如果你想学习软件测试,欢迎加入笔者的交流群:785128166,里面会有很多资源和大佬答疑解惑,我们一起交流一起学习!</p>
<p> </p><br>来源:程序园用户自行投稿发布,如果侵权,请联系站长删除<br>免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 自动化测试入门:从零开始搭建你的第一个WebUI项目