Behavior Driven Development 行为驱动开发入门

发布于 2024-03-05 00:28:57 字数 7625 浏览 24 评论 0

最近参加了 Toughtworks 的一次线下 Workshop,有幸头一次体验并实战了 BDD。感觉非常不错。

主题是:从 0 到 1 搭建自动化测试框架。围绕 BDD 进行,就如题目所说,翻译过来就是行为驱动开发,这是一种敏捷软件开发的技术,它鼓励软件项目中的 开发者、QA 和非技术人员或商业参与者之间的协作。BDD 最初是由 Dan North 在 2003 年命名,它包括验收测试和客户测试驱动等的极限编程的实践,作为对测试驱动开发的回应。在过去数年里,它得到了很大的发展。

在我的理解中,这个定义过程,弱化了当前需求职能在对接业务和研发过程中的翻译属性,而强化了解释属性。解释源头可以交由客户来定义。

前期基础环境准备如下:

为了方便 gradle 项目的构建,此处使用的 IDE 是 IntellJ IDEA ,我的版本是 15。

拿一个最小的测试用例来讲,可以将期解剖为 3 部分:

  1. 定义
  2. 执行
  3. 控制执行过程

项目结构如下,如上 3 部分对应的文件在截屏中有指示:

img

让我们来看看第一部分:定义

baidu.feture 文件:

Feature: Workshop baidu first case

  @first
  Scenario: Search cucumber
    Given : I open a baidu homepage "http://www.baidu.com"
    When : I input "cucumber" in searchbox
    Then : I will see page title contains "cucumber"

在此处我们定义了一条用例,描述是说:当用户打开百度搜索页的时候,输入一个关键字"cucumber"并点按搜索,然后检查搜索结果页的标题是否包含了刚才输入的关键字。

然后这个定义是如何启动的呢?看第二部分:执行

build.gradle 文件,重点看 cucumberBaidu() 方法:

apply plugin: 'java'
sourceCompatibility = 1.10
version = '1.0'

configurations {
    cucumberRuntime {
        extendsFrom testRuntime
    }
}

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.springframework:spring-context:4.2.1.RELEASE'
    compile 'junit:junit:4.12'
    compile 'org.seleniumhq.selenium:selenium-java:3.4.0'
    compile 'info.cukes:cucumber-core:1.1.2'
    compile 'info.cukes:cucumber-java:1.1.2'
    compile 'info.cukes:cucumber-junit:1.1.2'

    testCompile 'io.cucumber:cucumber-java:2.4.0'
    testCompile 'io.cucumber:cucumber-junit:2.4.0'
    testCompile 'junit:junit:4.12'
}

task cucumberBaidu() {
    dependsOn assemble, compileTestJava
    doLast {
        javaexec {
            main = "cucumber.api.cli.Main"
            classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output
            args = ['-f', 'pretty', '--glue', 'baidu_step', 'src/test/resources/cucumber/baidu.feature']
        }
    }
}

然后看第三部分,我们通过什么样的办法来自动化输入关键字并触发检索呢?

baidu_step.java 文件,定义中引号的部分转换为 java 方法中的入参。如下:

package baidu_step;

import cucumber.api.PendingException;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;

/**
 * Created by bianxh on 2018/3/31.
 */
public class baidu_step {

    WebDriver driver = null;

    public void initializeDriver()
    {
        driver = new ChromeDriver();
    }

    @Given("^: I open a baidu homepage \"([^\"]*)\"$")
    public void _I_open_a_baidu_homepage(String open_url) throws Throwable {
        initializeDriver();
        driver.get(open_url);
    }

    @When("^: I input \"([^\"]*)\" in searchbox$")
    public void _I_input_in_searchbox(String Keyword) throws Throwable {
        WebElement element = driver.findElement(By.cssSelector("#kw"));
        element.sendKeys(Keyword);
        WebElement element1 = driver.findElement(By.cssSelector("input#su"));
        // WebElement element1 = driver.findElement(By.cssSelector("input#su"));
        // WebElement element1 = driver.findElement(By.className("bg s_btn"));
        element1.click();

    }

    @Then("^: I will see page title contains \"([^\"]*)\"$")
    public void _I_will_see_page_title_contains(String Result) throws Throwable {
        // throw new PendingException();
        Thread.sleep(2000);
        System.out.println("title:" + driver.getTitle());
        driver.getTitle().contains(Result);
        driver.close();
    }
}

最后,我们在控制台执行:

bianxh:group_five_art bianxh$ gradle cucumberBaidu

> Task :cucumberBaidu 
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by cucumber.deps.com.thoughtworks.xstream.converters.collections.TreeMapConverter (file:/Users/bianxh/.gradle/caches/modules-2/files-2.1/info.cukes/cucumber-core/1.1.2/423d83b02d6a2409c21264023ad7b87d625be59e/cucumber-core-1.1.2.jar) to field java.util.TreeMap.comparator
WARNING: Please consider reporting this to the maintainers of cucumber.deps.com.thoughtworks.xstream.converters.collections.TreeMapConverter
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Starting ChromeDriver 2.36.540469 (1881fd7f8641508feb5166b7cae561d87723cfa8) on port 1468
Only local connections are allowed.
4 月 02, 2018 8:04:17 下午 org.openqa.selenium.remote.ProtocolHandshake createSession
信息: Detected dialect: OSS
title:cucumber_百度搜索

Feature: Workshop baidu first case

  @first
  Scenario: Search cucumber                                # src/test/resources/cucumber/baidu.feature:4
    Given : I open a baidu homepage "http://www.baidu.com" # baidu_step._I_open_a_baidu_homepage(String)
    When : I input "cucumber" in searchbox                 # baidu_step._I_input_in_searchbox(String)
    Then : I will see page title contains "cucumber"       # baidu_step._I_will_see_page_title_contains(String)


BUILD SUCCESSFUL in 7s
3 actionable tasks: 2 executed, 1 up-to-date

结果如下:

img

可以看到单个测试成功了。

注:通过 drive.close();可以关闭 chrome 浏览器。

那如果我们要定义一组 feature 来测试呢?

定义如下:

@first_group
Scenario Outline: multi-data test
    Given : I open a baidu homepage "<open_url>"
    When : Input "<Keyword>"
    Then : See "<Result>"

Examples:
    |open_url | Keyword | Result |
    |http://www.hao123.com | abc | abc |
    |http://www.hao123.com | abc1 | abc1 |

注意参数用<>进行了定义,执行代码中对多出来的部分进行控制,新增的代码如下:

// 2 feature
@When("^: Input \"([^\"]*)\"$")
public void _Input(String Keyword) throws Throwable {
    WebElement element = driver.findElement(By.cssSelector("#search-input"));
    element.sendKeys(Keyword);
    WebElement element1 = driver.findElement(By.cssSelector("#search-form > div.button-wrapper.g-ib > input"));
    element1.click();
}

@Then("^: See \"([^\"]*)\"$")
public void _See(String Result) throws Throwable {
    Thread.sleep(2000);
    System.out.println("title:" + driver.getTitle());
    driver.getTitle().contains(Result);
    driver.close();
}

注:关于截取网页元素的时候,可以通过 chrome 工具抓取 selector 来确保唯一性,这个一般可以应对后续的网页变化(网页更新时,测试用例代码改动较少)。

img

抓取后获取和使用办法如下:

WebElement element1 = driver.findElement(By.cssSelector("input#su"));
// 模拟点击事件
element1.click();

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

0 文章
0 评论
21 人气
更多

推荐作者

内心激荡

文章 0 评论 0

JSmiles

文章 0 评论 0

左秋

文章 0 评论 0

迪街小绵羊

文章 0 评论 0

瞳孔里扚悲伤

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文