1. 项目概述:从零到一,搞定你的第一个App UI自动化测试脚本
如果你是一名移动端测试工程师,或者是一名对质量保障感兴趣的后端、前端开发,那么“UI自动化测试”这个词你一定不陌生。它听起来很酷,能解放双手,让机器代替人工去点点点,但很多朋友在尝试迈出第一步时,就被Appium、环境配置、元素定位这些“拦路虎”给劝退了。今天,我们不谈那些庞大复杂的自动化测试框架,就聚焦一件事:如何从零开始,亲手写出并成功运行你的第一个App UI自动化测试脚本。
这个脚本的目标很简单:能自动打开一个App(比如手机自带的计算器),完成一个简单的操作(比如计算1+1),并验证结果是否正确。通过这个最小化的实践,你将打通从环境搭建、脚本编写到执行调试的完整链路,理解UI自动化测试的核心工作流。无论你是测试新手想入门,还是开发同学想为自己的App增加自动化回归能力,这篇内容都将提供一条清晰、可落地的路径。我会基于最主流的Appium + Python + Pytest技术栈来讲解,这是目前社区最活跃、资源最丰富的组合,能让你在遇到问题时快速找到解决方案。
2. 环境准备:搭建你的自动化“工作台”
写脚本之前,得先把“厨房”收拾好。环境配置是新手最容易卡住的地方,但只要我们按步骤来,完全可以避开大部分坑。我们的目标是搭建一个能够驱动手机(或模拟器)并执行Python脚本的环境。
2.1 核心工具安装与配置
首先,我们需要三样核心工具:Java、Android SDK、Appium Server。它们的关系可以这样理解:Appium Server是一个翻译官,它接收我们用Python写的指令(如“点击登录按钮”),并将其翻译成手机系统(Android/iOS)能理解的底层命令。而Android SDK提供了与Android设备通信的工具,Java则是Appium Server的运行环境。
第一步:安装Java JDKAppium Server是基于Node.js的,但其底层依赖Java环境。建议安装JDK 8或JDK 11(LTS版本)。
- 访问Oracle官网或AdoptOpenJDK等开源站点下载对应系统的JDK安装包。
- 安装后,需要配置环境变量。以Windows为例:
- 新建系统变量
JAVA_HOME,值为你的JDK安装路径(如C:\Program Files\Java\jdk1.8.0_301)。 - 在系统变量
Path中,添加%JAVA_HOME%\bin。
- 新建系统变量
- 打开命令行,输入
java -version和javac -version,能显示版本信息即说明配置成功。
第二步:安装Android SDKAndroid SDK我们通常不需要完整安装,只需要其命令行工具包(Command-line Tools)和必要的平台工具。
- 下载Android Command Line Tools。你可以通过Android Studio安装,或直接下载独立的命令行工具包。
- 解压到一个目录,例如
D:\Android\cmdline-tools。将其下的bin目录路径(如D:\Android\cmdline-tools\bin)添加到系统环境变量Path中。 - 我们需要两个关键工具:
adb(Android Debug Bridge) 和appium需要的uiautomatorviewer。它们通常在platform-tools和tools目录下。通过SDK管理器安装:- 打开命令行,运行
sdkmanager “platform-tools” “platforms;android-30” “emulator”(版本号可调整)。这会安装平台工具、指定API级别的系统镜像和模拟器。 - 安装后,将
platform-tools的路径(如D:\Android\platform-tools)也添加到Path环境变量。
- 打开命令行,运行
- 验证:命令行输入
adb version,应能显示版本号。
第三步:安装Appium ServerAppium Server有两种形式:桌面版(Appium Desktop)和命令行版(Appium Server)。对于初学者,强烈推荐使用Appium Desktop,它自带了一个元素定位器(Inspector),图形化界面更友好。
- 从Appium官网的Release页面下载对应系统的Appium Desktop安装包。
- 安装并启动。你会看到一个简单的界面,输入Host(默认127.0.0.1)和Port(默认4723),点击“Start Server”按钮。看到日志输出启动成功即可。保持这个窗口运行,我们的Python脚本将连接这个端口。
注意:环境变量配置后,务必关闭所有旧的命令行窗口并重新打开新的,以使配置生效。这是很多“命令找不到”问题的根源。
2.2 Python环境与依赖库安装
我们的脚本将用Python来写。Python环境的管理,我推荐使用Miniconda或Virtualenv创建独立的虚拟环境,避免包冲突。
- 安装Python:从Python官网下载3.7及以上版本(建议3.8或3.9)的安装包。安装时务必勾选“Add Python to PATH”。
- 创建虚拟环境(以conda为例):
# 创建一个名为appium_test的虚拟环境,指定Python版本 conda create -n appium_test python=3.8 # 激活环境 conda activate appium_test - 安装核心Python库:在激活的虚拟环境中,使用pip安装以下库。
pip install Appium-Python-Client pip install pytest pip install seleniumAppium-Python-Client:这是Appium官方提供的Python客户端库,封装了所有与Appium Server通信的协议。pytest:一个强大的测试框架,我们将用它来组织和运行我们的测试用例,它比Python自带的unittest更简洁灵活。selenium:虽然我们测的是App,但Appium遵循了WebDriver协议(由Selenium制定),很多底层交互依赖这个库。
至此,你的自动化“工作台”就基本搭建好了。接下来,我们需要一个被测设备。
2.3 被测设备准备与连接
你可以使用真机或模拟器。对于第一个脚本,我建议使用Android模拟器,因为它更干净、稳定,且可以随意重置。
- 使用Android Studio创建模拟器:打开Android Studio,进入“AVD Manager”(Android Virtual Device Manager)。点击“Create Virtual Device”,选择一个中等配置的设备(如Pixel 4),下载一个系统镜像(建议选择API Level 30左右的版本),完成创建。
- 启动模拟器:在AVD Manager中点击启动。等待模拟器完全启动进入主界面。
- 连接设备:在命令行中输入
adb devices。你应该能看到一个设备列表,其中包含你的模拟器,例如emulator-5554 device。这表示设备已连接,可以被ADB和Appium识别。 - 获取被测App信息:我们需要知道被测App的“包名”和“启动Activity”。对于系统自带计算器:
- 在模拟器中打开计算器App。
- 命令行输入:
adb shell dumpsys window | findstr mCurrentFocus(Windows) 或adb shell dumpsys window | grep mCurrentFocus(Mac/Linux)。 - 输出类似:
mCurrentFocus=Window{... com.android.calculator2/com.android.calculator2.Calculator}。这里com.android.calculator2就是包名(appPackage),com.android.calculator2.Calculator就是启动Activity(appActivity)。
如果你使用真机,需要先开启手机的“开发者选项”和“USB调试”模式,然后用USB线连接电脑,同样通过adb devices验证连接。
3. 脚本核心:编写你的第一个测试用例
环境就绪,设备连上,现在可以开始写代码了。我们将创建一个Python文件,例如test_first_calculator.py。
3.1 初始化驱动:建立与设备的会话
所有UI自动化的操作,都通过一个叫driver的对象来进行。初始化这个驱动,就是告诉Appium:“我要测试哪个设备上的哪个App”。
import pytest from appium import webdriver from appium.webdriver.common.appiumby import AppiumBy import time class TestCalculator: @classmethod def setup_class(cls): """整个测试类开始前执行一次,用于初始化驱动""" # 定义Desired Capabilities,这是一组键值对,用于告知Appium Server测试的上下文 desired_caps = { 'platformName': 'Android', # 测试平台 'platformVersion': '11', # 平台版本,根据你的模拟器/真机系统填写 'deviceName': 'emulator-5554', # 设备名,通过`adb devices`获取 'automationName': 'UiAutomator2', # Android自动化引擎,推荐使用UiAutomator2 'appPackage': 'com.android.calculator2', # 被测App包名 'appActivity': 'com.android.calculator2.Calculator', # 被测App启动Activity 'noReset': True, # 不重置App数据(避免每次清空缓存) 'newCommandTimeout': 600, # 命令超时时间(秒) 'unicodeKeyboard': True, # 启用Unicode输入法,用于输入中文等 'resetKeyboard': True # 测试结束后重置回默认输入法 } # 初始化驱动,连接本地Appium Server cls.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps) # 隐式等待,设置一个全局的元素查找超时时间 cls.driver.implicitly_wait(10) @classmethod def teardown_class(cls): """整个测试类结束后执行一次,用于清理,关闭驱动""" if cls.driver: cls.driver.quit()关键点解析:
- Desired Capabilities:这是Appium的核心配置。它本质上是一个JSON对象,告诉Appium Server你想要如何启动会话。
platformName,deviceName,appPackage,appActivity是必须项。 webdriver.Remote:这里我们连接的是本地(localhost)的Appium Server(端口4723)。如果你的Appium Server运行在其他机器上,需要修改这里的地址。implicitly_wait:隐式等待。它不是一个固定的休眠(time.sleep),而是设置一个最大等待时间。在查找元素时,如果元素没有立即出现,WebDriver会轮询查找,直到找到或超时。这比硬编码的time.sleep更智能、高效。
3.2 元素定位与操作:让脚本“看见”并“点击”
UI自动化的本质是定位元素和执行操作。定位元素就像是给脚本一双眼睛,告诉它要操作屏幕上的哪个按钮、哪个输入框。
Appium支持多种定位方式,最常用的是通过资源ID(resource-id)、文本(text)和XPath。我们可以使用Appium Desktop内置的Inspector来帮助我们定位元素。
- 启动Inspector:在Appium Desktop主界面,点击“Start Inspector Session”按钮。
- 配置Capabilities:在弹出的窗口中,填入和上面脚本中类似的Desired Capabilities(注意也要填对Appium Server地址和端口)。
- 连接并查看:点击“Start Session”,Appium会启动被测App,并打开一个可以查看UI层级的窗口。你可以点击屏幕上的元素,右侧会显示该元素的各种属性,如
resource-id,text,content-desc,class等。
假设我们通过Inspector发现,计算器上的数字“1”按钮,其resource-id是com.android.calculator2:id/digit_1,加号“+”按钮的resource-id是com.android.calculator2:id/op_add,等号“=”按钮的resource-id是com.android.calculator2:id/eq,结果文本框的resource-id是com.android.calculator2:id/result。
现在,我们来编写一个测试方法,实现1+1的计算:
def test_addition(self): """测试计算器加法功能:1 + 1 = 2""" driver = self.driver # 1. 定位并点击数字1 digit_1 = driver.find_element(AppiumBy.ID, 'com.android.calculator2:id/digit_1') digit_1.click() time.sleep(0.5) # 短暂等待,便于观察,实际项目中可优化 # 2. 定位并点击加号 + op_add = driver.find_element(AppiumBy.ID, 'com.android.calculator2:id/op_add') op_add.click() time.sleep(0.5) # 3. 再次点击数字1 digit_1.click() time.sleep(0.5) # 4. 定位并点击等号 = eq = driver.find_element(AppiumBy.ID, 'com.android.calculator2:id/eq') eq.click() time.sleep(1) # 等待计算完成 # 5. 定位结果框,获取文本并断言 result = driver.find_element(AppiumBy.ID, 'com.android.calculator2:id/result') actual_result = result.text print(f"计算结果为:{actual_result}") # 使用pytest的assert进行断言 assert actual_result == '2', f"断言失败:期望结果是'2',实际结果是'{actual_result}'"操作与定位详解:
driver.find_element(AppiumBy.ID, ‘id’):这是通过元素的资源ID进行定位,是最快、最稳定的定位方式。AppiumBy.ID对应Android中的resource-id属性。.click():对定位到的元素执行点击操作。result.text:获取元素的文本内容。对于计算器的结果框,这里应该显示计算结果的数字。assert:这是测试的核心。我们预期1+1等于2,所以断言结果文本等于‘2’。如果不等,测试将失败,并打印出自定义的错误信息。
3.3 运行与调试:见证自动化时刻
脚本写好了,让我们来运行它。
- 确保你的Appium Desktop Server正在运行(端口4723)。
- 确保你的Android模拟器或真机已启动并连接(
adb devices可见)。 - 在命令行中,切换到你的脚本所在目录,并激活之前创建的Python虚拟环境。
- 使用pytest运行测试:
pytest test_first_calculator.py -v-v参数会让输出更详细。
如果一切顺利,你将看到模拟器上的计算器被自动打开,数字1、加号、数字1、等号被依次点击,最后pytest输出绿色的PASSED字样。恭喜你,你的第一个UI自动化测试脚本成功运行了!
如果失败了,别担心。查看命令行输出的错误信息。常见问题有:
- 无法连接到Appium Server:检查Appium Desktop是否启动,端口是否为4723。
- 找不到设备:运行
adb devices确认设备在线且状态为device。 - 找不到元素:最常见。可能是定位符写错了,或者页面还没加载出来。检查Inspector中的属性值是否完全匹配(注意大小写和空格)。可以尝试增加隐式等待时间,或在关键操作前添加显式等待。
4. 从脚本到用例:优化与最佳实践
第一个脚本能跑通,只是一个开始。要写出健壮、可维护的自动化测试,我们需要引入一些工程化的思想和最佳实践。
4.1 使用Page Object模式组织代码
直接把所有定位和操作写在测试方法里,当页面元素变更时,你需要修改所有相关的测试方法,维护成本极高。Page Object (PO) 模式是UI自动化的标准设计模式。其核心思想是将页面对象和测试逻辑分离。
- 页面对象类:封装一个页面的所有元素定位和基本操作。
- 测试用例类:调用页面对象提供的方法来完成业务逻辑,并包含断言。
我们为计算器创建一个页面对象类calculator_page.py:
from appium.webdriver.common.appiumby import AppiumBy from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC class CalculatorPage: def __init__(self, driver): self.driver = driver # 定义页面元素定位器,统一管理 self.digit_1_locator = (AppiumBy.ID, 'com.android.calculator2:id/digit_1') self.digit_2_locator = (AppiumBy.ID, 'com.android.calculator2:id/digit_2') self.op_add_locator = (AppiumBy.ID, 'com.android.calculator2:id/op_add') self.op_sub_locator = (AppiumBy.ID, 'com.android.calculator2:id/op_sub') self.eq_locator = (AppiumBy.ID, 'com.android.calculator2:id/eq') self.result_locator = (AppiumBy.ID, 'com.android.calculator2:id/result') self.clear_locator = (AppiumBy.ID, 'com.android.calculator2:id/clr') # 封装页面操作 def click_digit_1(self): """点击数字1""" self.driver.find_element(*self.digit_1_locator).click() return self # 支持链式调用 def click_digit_2(self): self.driver.find_element(*self.digit_2_locator).click() return self def click_add(self): self.driver.find_element(*self.op_add_locator).click() return self def click_equals(self): self.driver.find_element(*self.eq_locator).click() return self def clear(self): self.driver.find_element(*self.clear_locator).click() return self def get_result(self): """获取计算结果,使用显式等待确保结果已更新""" # 显式等待:等待结果元素出现并且其文本不为空 result_element = WebDriverWait(self.driver, 10).until( EC.presence_of_element_located(self.result_locator) ) # 再等待一下,确保文本稳定(例如从‘’变成‘2’) WebDriverWait(self.driver, 5).until( lambda driver: result_element.text != '' ) return result_element.text然后,我们的测试脚本就变得非常简洁和易读:
import pytest from appium import webdriver from calculator_page import CalculatorPage # 导入页面对象 class TestCalculatorWithPO: ... # setup_class和teardown_class与之前相同 def test_addition_with_po(self): """使用Page Object模式测试加法""" calc_page = CalculatorPage(self.driver) # 链式调用,清晰表达业务流:1 + 1 = calc_page.click_digit_1().click_add().click_digit_1().click_equals() actual_result = calc_page.get_result() assert actual_result == '2' def test_subtraction_with_po(self): """测试减法:2 - 1 = 1""" calc_page = CalculatorPage(self.driver) calc_page.clear() # 清空之前的结果 calc_page.click_digit_2().click_subtract().click_digit_1().click_equals() assert calc_page.get_result() == '1'优势:
- 可维护性:元素定位符只存在于页面对象类中。如果计算器UI改版,按钮ID变了,你只需要修改
calculator_page.py中的一个地方。 - 可读性:测试用例读起来就像自然语言,清晰地描述了“做什么”,而不是“怎么做”。
- 复用性:
click_digit_1()这样的方法可以在多个测试用例中被复用。
4.2 引入显式等待与更智能的等待策略
之前我们用了implicitly_wait(隐式等待)和time.sleep(强制等待)。隐式等待是全局的,不够灵活;time.sleep是固定等待,效率低下且不可靠(网络或设备慢时可能不够用)。
显式等待(Explicit Wait)是更优的选择。它允许你为某个特定的条件设置等待,条件成立则立即继续,超时则抛出异常。我们在上面的get_result方法中已经使用了。
更常见的用法是封装一个查找元素的工具方法,它结合了显式等待:
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC def find_element_with_wait(driver, locator, timeout=10): """ 带显式等待的元素查找方法 :param driver: WebDriver实例 :param locator: 定位元组,如 (AppiumBy.ID, 'id') :param timeout: 超时时间,默认10秒 :return: 找到的WebElement """ try: element = WebDriverWait(driver, timeout).until( EC.presence_of_element_located(locator) ) return element except TimeoutException: # 可以在这里记录日志或截图,方便排查 driver.save_screenshot(f"element_not_found_{locator[1]}.png") raise TimeoutException(f"在{timeout}秒内未找到元素: {locator}")在页面对象中,可以这样使用:
def click_digit_1(self): element = find_element_with_wait(self.driver, self.digit_1_locator) element.click() return self常用等待条件(EC):
presence_of_element_located: 元素出现在DOM中(不一定可见)。visibility_of_element_located: 元素可见(长宽都大于0)。element_to_be_clickable: 元素可见且可点击。text_to_be_present_in_element: 元素的文本包含特定文字。
4.3 测试数据驱动与参数化
一个测试方法往往需要测试多组数据。例如,测试加法,我们想测1+1,2+2,3+5等等。使用pytest的@pytest.mark.parametrize装饰器可以轻松实现数据驱动。
import pytest class TestCalculatorDataDriven: ... # 初始化部分省略 @pytest.mark.parametrize("num1, num2, expected", [ (1, 1, 2), (2, 3, 5), (5, -2, 3), # 测试负数 (0, 9, 9), # 测试0 ]) def test_addition_with_data(self, num1, num2, expected): """数据驱动测试加法""" calc_page = CalculatorPage(self.driver) calc_page.clear() # 这里需要一个能点击任意数字的方法,我们可以扩展页面对象 # 假设我们新增了一个方法 click_digit(number) calc_page.click_digit(num1).click_add().click_digit(num2).click_equals() actual_result = int(calc_page.get_result()) # 结果转为整数比较 assert actual_result == expected, f"{num1} + {num2} 应该等于 {expected}, 但得到 {actual_result}"这需要你扩展CalculatorPage类,增加一个根据数字点击对应按钮的方法。这可以通过一个数字到定位符的映射字典来实现。数据驱动将测试逻辑与测试数据分离,使得增加新的测试用例只需要在参数列表中添加一行数据,极大地提高了测试的覆盖率和编写效率。
5. 常见问题排查与实战技巧
在实际编写和运行脚本时,你一定会遇到各种各样的问题。这里我总结了一些高频问题和处理技巧。
5.1 元素定位失败问题深度解析
这是UI自动化中最常见的问题,没有之一。
- 问题现象:
NoSuchElementException或TimeoutException。 - 排查步骤:
- 确认上下文:你确定当前在正确的页面/WebView/Native View吗?混合应用或H5页面中,需要在不同的上下文(Context)间切换。使用
driver.contexts和driver.current_context来检查和切换。 - 使用Appium Inspector复核:在脚本运行失败时,立刻用Appium Inspector连接当前会话(使用相同的Capabilities),查看此时的UI树结构,确认你使用的定位符是否还存在、是否唯一。动态ID或列表项是重灾区。
- 尝试其他定位方式:如果ID是动态的(每次打开都变化),尝试用XPath结合其他稳定属性,如
text、content-desc或class。例如://android.widget.Button[@text=‘确定’]。 - 等待策略:是否因为页面加载慢导致元素还没出现?将隐式等待调大,或使用前面提到的显式等待。
- 屏幕尺寸与坐标:极少数情况下,对于无法通过属性定位的元素(比如游戏界面),可以考虑使用坐标点击。通过
driver.get_window_size()获取屏幕尺寸,然后计算相对坐标。这是最后的手段,因为它在不同分辨率设备上不兼容。
- 确认上下文:你确定当前在正确的页面/WebView/Native View吗?混合应用或H5页面中,需要在不同的上下文(Context)间切换。使用
- 实战技巧:编写一个“安全查找”的装饰器或工具函数,在元素查找失败时自动截图并记录日志,这对于在CI/CD流水线中调试无头运行的测试非常有帮助。
5.2 等待与同步的进阶策略
除了显式等待,还有一些复杂场景需要处理:
- 等待页面跳转/活动切换:在点击一个按钮后,可能会启动新的Activity或加载新页面。可以等待旧Activity消失或新Activity出现。
# 假设点击登录按钮后,会跳转到MainActivity current_activity = driver.current_activity login_button.click() WebDriverWait(driver, 10).until( lambda x: x.current_activity != current_activity ) # 或者等待特定的Activity出现 WebDriverWait(driver, 10).until( EC.visibility_of_element_located((AppiumBy.ID, ‘main_page_element_id’)) ) - 等待网络请求完成:对于加载列表或提交表单的场景,可以等待某个代表加载完成的元素(如“加载中”提示)消失,或者等待列表项数量不再增加。
- 使用轮询代替固定等待:彻底避免使用
time.sleep。对于需要等待某个状态变化的场景,使用WebDriverWait配合自定义条件函数。
5.3 脚本稳定性提升与异常处理
不稳定的脚本比没有脚本更糟糕,因为它会带来误报,消耗信任。
- 异常处理与重试机制:对于网络波动、临时弹窗(如权限申请、升级提示)等导致的偶发性失败,可以引入重试逻辑。pytest有插件如
pytest-rerunfailures可以直接给用例添加重试注解@pytest.mark.flaky(reruns=2)。 - 用例独立性:每个测试用例都应该是独立的,不依赖其他用例的执行状态。这意味着需要在
setup_method(每个用例开始前)或teardown_method(每个用例结束后)进行清理,比如重置App、清理数据、回到主页面等。可以使用driver.reset()或driver.start_activity(package, activity)来重启App到初始状态。 - 截图与日志:在关键步骤(如用例开始、结束、断言前)和每次失败时自动截图,并配合详细的日志输出(可以使用Python的
logging模块),这是事后排查问题的黄金资料。def take_screenshot(driver, name): timestamp = time.strftime(“%Y%m%d_%H%M%S”) filename = f”screenshot_failure_{name}_{timestamp}.png” driver.save_screenshot(filename) print(f”截图已保存: {filename}”) # 也可以将文件名记录到测试报告中 - 处理系统弹窗与权限:在测试开始前,通过ADB命令预先授予App所需权限,可以避免测试过程中被权限弹窗打断。
adb shell pm grant <package_name> android.permission.<PERMISSION_NAME>
5.4 在CI/CD中集成与执行
个人跑通只是第一步,最终目标是集成到团队的持续集成流水线中,每次代码提交都能自动运行。
- 环境一致性问题:CI服务器(如Jenkins、GitLab CI)上的环境必须与本地开发环境一致。使用Docker镜像来封装测试环境(包含JDK、Android SDK、Appium、Python环境、依赖库)是最佳实践。可以寻找或自己构建包含这些工具的Docker镜像。
- 设备管理:在CI上可以使用Android模拟器,但需要以无头模式运行。也可以使用云测平台(如国内的Testin、腾讯WeTest,国外的BrowserStack、Sauce Labs)提供的真机设备池,它们通常提供了与Appium兼容的接口。
- 测试报告:使用
pytest-html或allure-pytest生成漂亮的HTML测试报告。Allure报告尤其强大,可以展示用例层级、步骤、截图、日志,非常适合团队协作和问题分析。 - 执行策略:在CI中,通常只运行冒烟测试或核心回归用例。可以将测试用例用pytest的mark功能分类(如
@pytest.mark.smoke),然后在CI脚本中指定只运行这些标记的用例:pytest -m smoke。
第一个脚本的完成,是你踏入App UI自动化测试大门的第一步。这条路的关键不在于记住所有API,而在于理解“驱动-定位-操作-断言”这个核心循环,并掌握Page Object、数据驱动、等待策略这些设计模式来构建健壮的测试套件。当你遇到问题时,多查官方文档,多利用Inspector工具,多思考元素背后的UI层级和状态变化,你会发现很多问题都能迎刃而解。自动化测试的最终目的不是取代手工测试,而是将测试人员从重复、枯燥的回归工作中解放出来,去从事更有价值的探索性测试和测试设计工作。