自动化测试用例结构分析
同学们大家好,欢迎来到今天的章节自动化测试用例结构分析,前面我们已经学习了如何使用 Selenium IDE 来录制测试用例。那么,录制完成后,接下来该做什么呢?当然是来分析一下录制出来的测试用例啦!了解它的结构是至关重要的一步,因为只有清楚了用例的组成部分,我们才能进一步优化它。那就让我们一起来探索这些用例的结构吧!
简介
在自动化测试中,自动化用例结构指的是测试用例的组织方式,它确保测试脚本的可读性、可维护性和可扩展性。
在自动化测试中,自动化用例结构指的是测试用例的组织方式,它确保测试脚本的可读性、可维护性和可扩展性。本节课我们会分三个部分来讲解。首先,我们会看看一个标准测试用例的结构到底是什么样的。接着,我们会对之前录制的测试用例进行详细分析,找出它的特点和问题。最后,在分析的基础上,对录制的测试用例进行一些优化,提升它的效率和可维护性。那我们就一步一步来吧!
标准的用例结构
- 用例标题
- 前提条件
- 用例步骤
- 预期结果
- 实际结果
用例标题 | 类型 | 前提条件 | 用例步骤 | 预期结果 | 实际结果 |
---|---|---|---|---|---|
搜狗搜索功能 | 正例 | 进入搜狗首页 | 1. 输入搜索关键词 2.按下回车键 |
1. 搜索成功 2. 搜索结果列表包含关键字 |
首先,我们来了解一下标准的用例结构。一个完整的测试用例通常包含以下几个部分:用例标题、前提条件、用例步骤、预期结果和实际结果。这些部分共同构成了一个清晰、可执行的测试用例。比如,这里有一个关于搜狗搜索功能的用例示例:用例标题是‘搜狗搜索功能’,类型是正例,前提条件是用户需要先进入搜狗首页。接着,在用例步骤中,我们列出了两步操作,第一步是输入搜索关键词,第二步是按下回车键。而在预期结果中,系统应该能够成功完成搜索,并且搜索结果列表中包含输入的关键词。这种结构不仅清晰易懂,还能保证测试的完整性。接下来,我们深入分析这一结构的每个部分,看看它们是如何协同工作的吧!
用例结构对比
自动化测试用例 | 作用 | |
---|---|---|
用例标题 | 测试包、文件、类、方法名称 | 用例的唯一标识 |
前提条件 | setup、setup_class(Pytest); BeforeEach、BeforeAll(JUnit) |
测试用例前的准备动作,比如读取数据或者driver的初始化 |
用例步骤 | 测试方法内的代码逻辑 | 测试用例具体的步骤行为 |
预期结果 | assert 实际结果 = 预期结果 | 断言,印证用例是否执行成功 |
实际结果 | assert 实际结果 = 预期结果 | 断言,印证用例是否执行成功 |
后置动作 | teardown、teardown_class(Pytest); @AfterEach、@AfterAll(JUnit) |
脏数据清理、关闭driver进程 |
自动化测试用例的结构其实和功能测试用例非常相似,它包含用例标题、前提条件、测试步骤、预期结果和实际结果,同时多了一个非常重要的部分——后置动作。用例标题是测试用例的唯一标识,通过组合测试的包名、文件名、类名和方法名来定位;前提条件是用例执行前的准备工作,比如数据初始化或 WebDriver 的配置,通常在 setUp 或类似方法中实现;测试步骤对应用例的核心操作逻辑,比如接口调用或页面操作;预期结果和实际结果则通过断言来验证测试是否成功,比如用 assert 判断是否匹配;最后是后置动作,负责清理脏数据、关闭驱动等资源管理工作,确保环境整洁。总体来看,自动化测试用例的结构清晰,逻辑严谨,是功能测试用例的升级版本,更适合自动化执行的场景。
IDE 录制脚本
- 脚本步骤: - 访问搜狗网站 - 搜索框输入“霍格沃兹测试开发” - 点击搜索按钮
录制 python 脚本
# Generated by Selenium IDE
import pytest
import time
import json
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
class Test():
def setup_method(self, method):
self.driver = webdriver.Chrome()
self.vars = {}
def teardown_method(self, method):
self.driver.quit()
def test_sougou(self):
# 打开网页,设置窗口
self.driver.get("https://www.sogou.com/")
self.driver.set_window_size(1235, 693)
# 输入搜索信息
self.driver.find_element(By.ID, "query").click()
self.driver.find_element(By.ID, "query").send_keys("霍格沃兹测试开发")
# 点击搜索
self.driver.find_element(By.ID, "stb").click()
element = self.driver.find_element(By.ID, "stb")
actions = ActionChains(self.driver)
actions.move_to_element(element).perform()
那接下来我们以一个真实的脚本为例,来分析它的结构。这是上一节课我们使用 IDE 录制的一个脚本,脚本的操作流程是:访问搜狗首页,在搜索框输入“霍格沃兹测试开发”,然后点击搜索按钮。我们直接查看录制好的脚本代码,分析它是否符合前面提到的自动化测试用例几大要素。首先,可以看到脚本有明确的类名和方法名,这些信息组合在一起构成了独一无二的用例标题,这一点是符合的。然后我们看前提条件,脚本中在 setUp 方法里初始化了 driver,这说明它包含了测试前的准备工作。接下来是测试步骤,在测试方法中可以清晰地看到它执行了打开网页、输入搜索词、点击按钮等操作,这部分逻辑是完整的。接着,我们检查预期结果和实际结果的体现,也就是断言,发现这个脚本缺少断言信息,无法判断用例是执行成功还是失败,这是一个需要优化的地方。最后是后置动作,脚本包含关闭驱动的逻辑,说明这一部分也符合标准。总体来说,这个脚本的结构基本完整,但缺乏断言信息。接下来我们将为这个脚本添加断言,解决用例无法明确执行结果的问题,并进一步完善它的结构。
python 脚本优化
import pytest
import time
import json
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
class TestDemo01():
def setup_method(self, method):
# 实例化chromedriver
self.driver = webdriver.Chrome()
# 添加全局隐式等待
self.driver.implicitly_wait(5)
def teardown_method(self, method):
# 关闭driver
self.driver.quit()
def test_demo01(self):
# 访问网站
self.driver.get("https://www.baidu.com/")
# 设置窗口
self.driver.set_window_size(1330, 718)
# 点击输入框
self.driver.find_element(By.ID, "kw").click()
# 输入框输入信息
self.driver.find_element(By.ID, "kw").send_keys("霍格沃兹测试开发")
# 点击搜索按钮
self.driver.find_element(By.ID, "su").click()
# 等待界面加载
time.sleep(5)
# 元素定位后获取文本信息
res = self.driver.find_element(By.XPATH,"//*[@id='1']/h3/a").get_attribute("text")
# 打印文本信息
print(res)
# 添加断言
assert "霍格沃兹测试开发" in res
# 查看界面展示
time.sleep(5)
首先,我们在这里做一个简单的判断测试,就是判断搜索结果列表中是否包含我们输入的关键词‘霍格沃兹测试开发’。我们可以通过进入搜狗的搜索页面,输入关键词,然后检查搜索结果中是否有匹配的内容。在这个例子中,我们发现搜索结果的第一个条目有一个 E-M 标签,可以用来定位这个关键字。接下来,我们要做的就是定位到这个标签并提取它的文本内容。我们可以使用 Selenium 提供的定位方法,像是通过 CS-S Selector 来定位到该标签,并使用 点text 方法获取文本内容。然后,我们来做一个断言,判断获取到的文本是否等于‘霍格沃兹测试开发’。这个断言就是用来验证实际结果和预期结果是否一致。断言成功意味着测试用例通过,反之则会失败。接着,我们再尝试加一些其他的字符,比如在‘霍格沃兹测试开发’后面加上一些额外的文字,来验证如果搜索结果不匹配时,测试是否会失败。执行时,如果测试失败,系统会给出详细的错误信息,比如它找到了与预期不匹配的结果。通过这个简单的测试用例,我们可以了解到自动化测试用例的标准结构。首先是用例标题,通过包名、文件名、类名、方法名来唯一标识这个用例。然后是前提条件,比如 driver 的初始化。接下来是用例步骤,具体的测试行为就是我们的代码逻辑。接着是预期结果和实际结果,通过断言来验证是否符合预期。最后是后置动作,比如退出浏览器,清理环境。这个结构帮助我们更好地管理测试用例,确保测试的完整性和高效性。
录制 Java 脚本
// Generated by Selenium IDE
import org.junit.Test;
import org.junit.Before;
import org.junit.After;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Alert;
import org.openqa.selenium.Keys;
import java.util.*;
import java.net.MalformedURLException;
import java.net.URL;
public class TestSogouTest {
private WebDriver driver;
private Map<String, Object> vars;
JavascriptExecutor js;
@Before
public void setUp() {
driver = new ChromeDriver();
js = (JavascriptExecutor) driver;
vars = new HashMap<String, Object>();
}
@After
public void tearDown() {
driver.quit();
}
@Test
public void testSogou() {
driver.get("https://www.sogou.com/");
driver.manage().window().setSize(new Dimension(1671, 1417));
driver.findElement(By.id("query")).sendKeys("霍格沃兹测试开发");
driver.findElement(By.id("query")).sendKeys(Keys.ENTER);
}
}
接下来,我们来看一下关于 Java 版本的实现。其实,从自动化测试的角度来看,无论是 Python 还是 Java,它们的逻辑都是类似的,核心思想都是一样的,只不过是通过不同的语言来实现。所以,使用 Java 的同学可以参考接下来的代码示例和 pom 文件中的依赖配置,来快速搭建自己的测试脚本。虽然语言不同,但自动化测试的步骤、结构和流程都是一致的,掌握了其中的原理,切换语言就不再是问题了。
Java pom 依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>beginner</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>11</java.version>
<!-- 使用 Java 11 语言特性 ( -source 11 ) 并且还希望编译后的类与 JVM 11 ( -target 11 )兼容,您可以添加以下两个属性,它们是默认属性插件参数的名称-->
<maven.compiler.target>11</maven.compiler.target>
<!-- 对应junit Jupiter的版本号;放在这里就不需要在每个依赖里面写版本号,导致对应版本号会冲突-->
<junit.jupiter.version>5.8.2</junit.jupiter.version>
<maven.compiler.version>3.8.1</maven.compiler.version>
<maven.surefire.version>3.0.0-M5</maven.surefire.version>
<hamcrest.version>2.2</hamcrest.version>
<!-- plugins -->
<maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
<!-- log日志 -->
<slf4j.version>2.0.0-alpha7</slf4j.version>
<logback.version>1.3.0-alpha16</logback.version>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.2.1</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.jupiter.version}</version>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>${junit.jupiter.version}</version>
</dependency>
</dependencies>
<build>
<!-- maven 运行的依赖插件 -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<parameters>true</parameters>
<source>11</source>
<target>11</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M7</version>
<configuration>
<includes>
<include>**/*Test.java</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
</project>
接下来,让我们一起来看看 Java 项目中 Pom 文件的结构和依赖配置,这也是自动化测试项目的核心部分。Pom 文件,也就是 Maven 的项目对象模型文件,主要用于管理项目的依赖、插件和构建配置。首先,在 properties 部分,我们定义了一些关键属性,比如 java点version 指定了 Java 11 的版本,而 junit点jupiter点version 和 maven点compiler点version 则是分别为 JUnit 和 Maven 编译器插件定义的版本号。通过这些属性,你可以避免在每个依赖中重复指定版本,同时也能有效解决依赖冲突的问题。接着是 dependencies 部分,这里添加了一些核心依赖,比如 selenium杠java 用于支持 Selenium 的核心功能,junit杠jupiter杠engine 用于运行基于 JUnit 5 的测试用例,S-L-F-Four-J杠api 和 logback杠classic 则是用于日志记录和管理。通过这些依赖配置,你可以快速搭建一个功能完整的测试框架。最后是 build 部分,我们在 plugins 标签中配置了 Maven 的编译器插件和 Surefire 插件。其中,编译器插件设置了 Java 编译版本和编码格式,而 Surefire 插件则用于执行测试用例,支持匹配以 *Test点java 结尾的测试类文件。通过这样一个清晰的 Pom 文件配置,你可以高效地管理测试项目的依赖和构建过程。不仅如此,它还能帮助我们保持项目的可维护性和可扩展性。
Java 脚本优化
- 隐式等待(了解即可)
- 断言信息
// Generated by Selenium IDE
import org.junit.Test;
import org.junit.Before;
import org.junit.After;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Alert;
import org.openqa.selenium.Keys;
import java.time.Duration;
import java.util.*;
import java.net.MalformedURLException;
import java.net.URL;
import static org.junit.Assert.assertEquals;
public class TestSogouTest {
private WebDriver driver;
private Map<String, Object> vars;
JavascriptExecutor js;
@Before
public void setUp() {
// 实例化chromedriver
driver = new ChromeDriver();
// 添加全局隐式等待
js = (JavascriptExecutor) driver;
vars = new HashMap<String, Object>();
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
}
@After
// 关闭driver
public void tearDown() {
driver.quit();
}
@Test
public void testSogou() {
// 打开网页
driver.get("https://www.sogou.com/");
// 设置窗口
driver.manage().window().setSize(new Dimension(1671, 1417));
// 输入霍格沃兹测试开发
driver.findElement(By.id("query")).sendKeys("霍格沃兹测试开发");
// 回车搜索
driver.findElement(By.id("query")).sendKeys(Keys.ENTER);
// 获取搜索的文本结果
String text = driver.findElement(By.cssSelector("#sogou_vr_30000000_0 > em")).getText();
// 断言是否包含期望文本
assertEquals("霍格沃兹测试开发", text);
}
}
在这段 Java 示例代码中,我们对脚本做了与Python版本一样的优化,核心改进包括添加隐式等待和断言信息。隐式等待提升了脚本的稳定性,避免因元素加载延迟导致失败;断言功能确保测试结果的准确性,通过验证搜索结果包含预期关键字来判断功能是否正常。此外,将初始化和清理操作分别放在 setUp 和 tearDown 方法中,简化了代码结构,增强了复用性和可维护性。这样的优化让脚本更加规范、高效,测试结果也更为可靠。你也可以参考这些思路,进一步完善自己的脚本,相信通过本章的学习,你一定对 Web 自动化有了更深的理解!现在是巩固知识的最佳时机,多加练习,将理论转化为实践吧!持续精进,你会发现自动化测试变得越来越得心应手。
总结
- 标准的用例结构
- IDE 录制脚本