写点什么

软件测试学习笔记丨测试框架体系 TDD DDT BDD ATDD 介绍

作者:测试人
  • 2024-04-10
    北京
  • 本文字数:6497 字

    阅读完需:约 21 分钟

本文转自测试人社区,原文链接:https://ceshiren.com/t/topic/30293

测试框架体系 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

@Testvoid 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.pydef inc(x):    return x + 1
def test_answer(): assert inc(3) == 5
#UnitTestimport 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 PASSWORDInvalid User Name invalid ${VALID PASSWORD}Invalid Password ${VALID USER} invalidInvalid User Name and Password invalid invalidEmpty 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 TestNGRobotFramework DDTYAML 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"]
复制代码
  • 数据驱动风格为什么广受欢迎


  • 维护成本最低,录制回放技术越来越成熟,可以与数据驱动很好的结合。低代码、用例生成技术的流行,会让数据驱动风格更受欢迎。

软件测试开发免费视频教程分享


发布于: 刚刚阅读数: 4
用户头像

测试人

关注

专注于软件测试开发 2022-08-29 加入

霍格沃兹测试开发学社,测试人社区:https://ceshiren.com/t/topic/22284

评论

发布
暂无评论
软件测试学习笔记丨测试框架体系 TDD DDT BDD ATDD 介绍_软件测试_测试人_InfoQ写作社区