测试框架体系 TDD DDT BDD ATDD 介绍
-
测试框架是什么
测试框架是一组用于创建和设计测试用例的指南或规则。框架由旨在帮助 QA 专业人员更有效地测试的实践和工具的组合组成。 这些指南可能包括编码标准、测试数据处理方法、对象存储库、存储测试结果的过程或有关如何访问外部资源的信息。 -
测试框架的价值
测试框架是任何成功的自动化测试过程的重要组成部分。它们可以降低维护成本和测试工作,并为寻求优化其敏捷流程的 QA 团队提供更高的投资回报率 (ROI)。 -
测试框架是什么
测试框架是一组用于创建和设计测试用例的指南或规则。框架由旨在帮助 QA 专业人员更有效地测试的实践和工具的组合组成。 这些指南可能包括编码标准、测试数据处理方法、对象存储库、存储测试结果的过程或有关如何访问外部资源的信息。 -
测试框架的价值
测试框架是任何成功的自动化测试过程的重要组成部分。它们可以降低维护成本和测试工作,并为寻求优化其敏捷流程的 QA 团队提供更高的投资回报率 (ROI)。 -
测试框架的收益
Improved test efficiency 提高测试效率
Lower maintenance costs 降低维护成本
Minimal manual intervention 最少的人工干预
Maximum test coverage 最大测试覆盖率
Reusability of code 代码的可重用性 -
常见测试框架类型
框架 说明
TDD 代码风格
DDT 数据驱动风格
ATDD 验收测试驱动开发
BDD 行为驱动开发 (Behavior-driven development)
MBT Model Based Testing 基于模型的测试 -
TDD定义
测试驱动开发(TDD)是一个软件开发过程,在软件完全开发之前,将软件需求转换为测试用例,并通过针对所有测试用例重复测试软件来跟踪所有软件开发。这与首先开发软件和稍后创建测试用例相反 -
TDD 流程 (JUnit TestNG | Pytest UnitTest)
单元测试
重构
覆盖率
可测性提升
模型驱动设计
- 代表作 JUnit TestNG
@Test
void standardAssertions() {
assertEquals(2, calculator.add(1, 1));
assertEquals(4, calculator.multiply(2, 2),
"The optional failure message is now the last parameter");
assertTrue('a' < 'b', () -> "Assertion messages can be lazily evaluated -- "
+ "to avoid constructing complex messages unnecessarily.");
}
- TestNG
package example1;
import org.testng.annotations.*;
public class SimpleTest {
@BeforeClass
public void setUp() {
// code that will be invoked when this test is instantiated
}
@Test(groups = { "fast" })
public void aFastTest() {
System.out.println("Fast test");
}
@Test(groups = { "slow" })
public void aSlowTest() {
System.out.println("Slow test");
}
}
- 代表作 Pytest UnitTest
# content of test_sample.py
def inc(x):
return x + 1
def test_answer():
assert inc(3) == 5
#UnitTest
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
-
BDD定义
在软件工程中,行为驱动开发 (BDD) 是一种敏捷软件开发过程,它鼓励软件项目中的开发人员、质量保证专家和客户代表之间进行协作。它鼓励团队使用对话和具体示例来形成对应用程序应该如何运行的共同理解。它源于测试驱动开发 (TDD)。行为驱动开发将 TDD 的通用技术和原则与领域驱动设计和对象的思想相结合面向分析和设计,为软件开发和管理团队提供共享工具和共享流程,以便在软件开发方面进行协作。 -
BDD VS TDD
-
BDD 相关框架
JBehave
Cucumber
Mspec
Specflow -
Cucumber
Cucumber 测试用例 Scenario 场景
-
Cucumber 测试用例步骤定义
public class ExampleSteps {
private final WebDriver driver = new FirefoxDriver();
@Given("I am on the Google search page")
public void I_visit_google() {
driver.get("https://www.google.com");
}
@When("I search for {string}")
public void search_for(String query) {
WebElement element = driver.findElement(By.name("q"));
// Enter something to search for
element.sendKeys(query);
// Now submit the form. WebDriver will find the form for us from the element
element.submit();
}
@Then("the page title should start with {string}")
public void checkTitle(String titleStartsWith) {
// Google's search is rendered dynamically with JavaScript
// Wait for the page to load timeout after ten seconds
new WebDriverWait(driver,10L).until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {
return d.getTitle().toLowerCase().startsWith(titleStartsWith);
}
});
}
@After()
public void closeBrowser() {
driver.quit();
}
}
-
ATDD 定义
验收测试驱动开发 (ATDD) 是一种基于业务客户、开发人员和测试人员之间沟通的开发方法。ATDD 包含许多与示例规范 (SBE)、行为驱动开发 (BDD)、示例驱动开发 (EDD)、和支持驱动开发(也称为故事测试驱动开发(SDD)。所有这些流程都有助于开发人员和测试人员在实施之前了解客户的需求,并使客户能够使用他们自己的领域语言进行交流。 -
ATDD 相关工具
FitNesse:完全集成的独立 wiki 和验收测试框架
Robotframework 介绍:Robot Framework 是一个基于 Python 的可扩展关键字驱动的自动化框架,用于验收测试、验收测试驱动开发 (ATDD)、行为驱动开发 (BDD) 和机器人流程自动化 (RPA)。
Robot Framework 是一个通用的开源自动化框架。它可用于测试自动化和机器人流程自动化 (RPA)。Robot Framework 具有简单的语法,使用人类可读的关键字。它的功能可以通过使用 Python、Java 或许多其他编程语言实现的库来扩展。Robot Framework 有一个丰富的生态系统,由作为独立项目开发的库和工具组成。
-
Robotframework 测试用例
*** Settings ***
Documentation Simple example using SeleniumLibrary.
Library SeleniumLibrary
*** Variables ***
${LOGIN URL} http://localhost:7272
${BROWSER} Chrome
*** Test Cases ***
Valid Login
Open Browser To Login Page
Input Username demo
Input Password mode
Submit Credentials
Welcome Page Should Be Open
[Teardown] Close Browser
*** Keywords ***
Open Browser To Login Page
Open Browser ${LOGIN URL} ${BROWSER}
Title Should Be Login Page
Input Username
[Arguments] ${username}
Input Text username_field ${username}
Input Password
[Arguments] ${password}
Input Text password_field ${password}
Submit Credentials
Click Button login_button
Welcome Page Should Be Open
Title Should Be Welcome Page
- 数据驱动风格
*** Settings ***
Test Template Login with invalid credentials should fail
*** Test Cases *** USERNAME PASSWORD
Invalid User Name invalid ${VALID PASSWORD}
Invalid Password ${VALID USER} invalid
Invalid User Name and Password invalid invalid
Empty User Name ${EMPTY} ${VALID PASSWORD}
Empty Password ${VALID USER} ${EMPTY}
Empty User Name and Password ${EMPTY} ${EMPTY}
- BDD 风格
*** Test Cases ***
Valid Login
Given login page is open
When valid username and password are inserted
and credentials are submitted
Then welcome page should be open
-
ATDD VS BDD
TDD ATDD BDD
受众 开发 开发 测试 客户 开发 测试 客户
过程 代码 DSL 行为
目标 代码调用功能 验收测试 需求 需求 -
MBT Model Based Testing
model-based testing
GraphWalker, an open-source model-based testing tool
-
edge 代表步骤
一条边代表一个动作,一个过渡。 操作可以是 API 调用、按钮单击、超时等。任何将您的被测系统移动到您想要验证的新状态的任何事情。但请记住,边缘没有进行验证。这只发生在顶点。 -
vertex 代表断言
一个顶点代表验证,一个断言。 验证是您的代码中有断言的地方。在这里,您可以验证 API 调用是否返回正确的值、按钮单击是否确实关闭了对话框,或者在应该发生超时时,被测系统触发了预期的事件。 -
graph 代表测试用例集
模型是一个图,它是一组顶点和边 从模型中,GrapWalker 将生成一条通过它的路径。一个模型有一个起始元素,一个规则如何生成路径的生成器,以及告诉 GraphWalker 何时停止生成路径的相关停止条件。 -
测试用例样板生成
@GraphWalker(value = "random(edge_coverage(100))")
public class OwnerInformationTest extends ExecutionContext implements OwnerInformation {
private static final Logger log = LoggerFactory.getLogger(OwnerInformationTest.class);
@Override
public void v_OwnerInformation() {
$(By.tagName("h2")).shouldHave(text("Owner Information"));
setAttribute("numOfPets", Value.asValue($$x("//table/tbody/tr/td//dl").size()));
log.info("Number of pets: " + getAttribute("numOfPets"));
}
@Override
public void e_UpdatePet() {
$("button[type=\"submit\"]").click();
}
@Override
public void v_FindOwners() {
$(By.tagName("h2")).shouldHave(text("Find Owners"));
$(By.tagName("h2")).shouldBe(visible);
}
@Override
public void e_EditPet() {
$(By.linkText("Edit Pet")).click();
}
@Override
public void e_AddNewPet() {
$(By.linkText("Add New Pet")).click();
}
@Override
public void e_AddVisit() {
$(By.linkText("Add Visit")).click();
}
@Override
public void e_FindOwners() {
$("[title='find owners']").click();
}
@Override
public void e_AddPetSuccessfully() {
Date date = new Faker().date().past( 365 * 20, TimeUnit.DAYS);
SimpleDateFormat sdf;
sdf = new SimpleDateFormat("yyyy-MM-dd");
String birthData = sdf.format(date);
$(By.id("birthDate")).clear();
$(By.id("birthDate")).sendKeys(birthData + Keys.ENTER);
$(By.id("name")).clear();
$(By.id("name")).sendKeys(new Faker().name().fullName());
$(By.id("type")).selectOption(new Faker().number().numberBetween(0,5));
$(By.cssSelector("button[type=\"submit\"]")).click();
}
@Override
public void v_NewPet() {
$(By.tagName("h2")).shouldHave(text("New Pet"));
$(".has-feedback").shouldBe(visible);
}
@Override
public void e_VisitAddedSuccessfully() {
$(By.id("description")).clear();
$(By.id("description")).sendKeys(new Faker().lorem().word());
$("button[type=\"submit\"]").click();
}
@Override
public void v_NewVisit() {
$(By.tagName("h2")).shouldHave(text("New Visit"));
}
@Override
public void v_Pet() {
$(By.tagName("h2")).shouldHave(text("Pet"));
}
@Override
public void e_AddPetFailed() {
$(By.id("name")).clear();
$(By.id("birthDate")).clear();
$(By.id("birthDate")).sendKeys("2015/02/05" + Keys.ENTER);
$(By.id("ui-datepicker-div")).shouldBe(not(visible));
$(By.id("type")).selectOption("dog");
$("button[type=\"submit\"]").click();
}
@Override
public void e_VisitAddedFailed() {
$(By.id("description")).clear();
$("button[type=\"submit\"]").click();
}
}
-
DDT
数据驱动测试(DDT),也称为表驱动测试或参数化测试,是一种软件测试方法,用于计算机软件的测试,用于描述使用条件表直接作为测试输入和可验证输出完成的测试以及测试环境设置和控制没有硬编码的过程. -
DDT 相关工具
DDT 是一种实践,可以跟很多框架结合
单元测试结合 DDT:JUnit4 JUnit5 TestNG
RobotFramework DDT
YAML JSON CSV 驱动 HttpRunner -
数据驱动应用案例
HttpRunner 可以根据代理抓包自动生成测试用例
YAPI、Swagger 等工具可以根据数据自动生成测试用例代码
JVM-Sandbox-Repeater Gor 录制工具可以把请求保存为测试用例并重放以实现快速回归测试 -
HttpRunner 测试框架
-
HttpRunner 测试用例
config:
name: "request methods testcase with functions"
variables:
foo1: config_bar1
foo2: config_bar2
expect_foo1: config_bar1
expect_foo2: config_bar2
base_url: "https://postman-echo.com"
verify: False
export: ["foo3"]
teststeps:
- name: get with params
variables:
foo1: bar11
foo2: bar21
sum_v: "${sum_two(1, 2)}"
request:
method: GET
url: /get
params:
foo1: $foo1
foo2: $foo2
sum_v: $sum_v
headers:
User-Agent: HttpRunner/${get_httprunner_version()}
extract:
foo3: "body.args.foo2"
validate:
- eq: ["status_code", 200]
- eq: ["body.args.foo1", "bar11"]
- eq: ["body.args.sum_v", "3"]
- eq: ["body.args.foo2", "bar21"]
- name: post raw text
variables:
foo1: "bar12"
foo3: "bar32"
request:
method: POST
url: /post
headers:
User-Agent: HttpRunner/${get_httprunner_version()}
Content-Type: "text/plain"
data: "This is expected to be sent back as part of response body: $foo1-$foo2-$foo3."
validate:
- eq: ["status_code", 200]
- eq:
[
"body.data",
"This is expected to be sent back as part of response body: bar12-$expect_foo2-bar32.",
]
- name: post form data
variables:
foo2: bar23
request:
method: POST
url: /post
headers:
User-Agent: HttpRunner/${get_httprunner_version()}
Content-Type: "application/x-www-form-urlencoded"
data: "foo1=$foo1&foo2=$foo2&foo3=$foo3"
validate:
- eq: ["status_code", 200]
- eq: ["body.form.foo1", "$expect_foo1"]
- eq: ["body.form.foo2", "bar23"]
- eq: ["body.form.foo3", "bar21"]
- 数据驱动风格为什么广受欢迎
维护成本最低,录制回放技术越来越成熟,可以与数据驱动很好的结合。低代码、用例生成技术的流行,会让数据驱动风格更受欢迎。