BDD行为驱动简介及Pytest-bdd基础使用

pytest-bdd.png

运行环境: pip insall pytest pytest-bdd pytest-selenium

BDD介绍

BDD行为驱动是一种敏捷开发模式, 重点在于消除开发/测试对需求了解的歧义及用户场景的验证.

需求描述/用户场景

BDD提供一套标准的需求及用户场景表达语法, 一般为Feature(需求), Scenario(场景), Given(假设,预置条件), When(操作步骤), Then(验证及清理), 如下为一个需求描述(有的公司称为需求卡片):

文件名: educa.feature 需求使用专门的.feature作为后缀

Feature: educa在线课程网站需求
    需求描述: 提供后台添加课程及课程内容, 前台学生浏览课程, 加入课程后可查看课程详情

Scenario: 通过educa后台添加课程
    Given 用户:hanzhichao, 密码:hanzhichao123
    And 分类:接口测试,标题:Python接口测试教程,描述:作者,临渊
    When 登录educa后台
    And 点击:Courses模块->点击新增按钮
    And 作者选择当前<用户>,选择<分类>,输入<标题>,<描述>,点击保存
    Then 页面中应存在名称为<标题>的链接
    And 删除该课程

#Scenario: 学生选课
#    ...

  • 一个需求文件中只能有一个Feature字段, 可以包含多个Scenario(用户场景)
  • Given->When->Then类似与准备->执行->验证/清理的流程
  • Given: 一般可以用来做预置条件/数据准备, 下面第一个And也属于Given
  • When下面的量And都属于When, 一般是操作步骤, <用户>等只是用来提醒使用的是Given中的数据, 也可以不使用<>
  • Then: 一般用于验证结果(断言), 也可以进行清理数据

场景解析/实现

单有场景文件是不能执行的, 在BDD的初级使用中, 测试同学还需要将每个场景文件中的描述翻译成具体的页面操作, 每一句对应一个函数, 下面是使用pytest-bdd对上诉educt.feature的解析实现:

# file_name: scenario_steps.py
from pytest_bdd import given, when, then, parsers  
from selenium.webdriver.support.select import Select
from selenium.webdriver.support import expected_conditions as EC


@given(parsers.parse("用户:{username}, 密码:{password}"))
def user(username, password):  # 类似一个pytest的fixture方法, 其他步骤可以使用其返回值
    return dict(username=username, password=password)


@given(parsers.parse("分类:{category},标题:{title},描述:{description}"))
def course(category, title, description):
    return dict(category=category, title=title, description=description)


@when("登录educa后台")  # 固定操作,不需要获取参数则不用parsers.parse()
def login(selenium, user):  # 使用上面user函数的返回数据, selenium为浏览器driver(来着:pytest-selenium)
    selenium.get("http://qaschool.cn:8000/admin/")
    selenium.find_element_by_id("id_username").send_keys(user['username'])
    selenium.find_element_by_id("id_password").send_keys(user['password'])
    selenium.find_element_by_class_name("submit-row").click()


@when(parsers.parse("点击:{module}模块->点击新增按钮"))
def add_course(selenium, module):
    selenium.find_element_by_link_text(module).click()  # 点击'Courses'链接
    selenium.find_element_by_class_name("addlink").click()  # 点击'新增 COURSE'按钮


@when("作者选择当前<用户>,选择<分类>,输入<标题>,<描述>,点击保存")  # 也可以不使用<>, 要与场景中一致, 使用<>只是提示是从Given的数据中获取
def edit_course(selenium, user, course):  # 使用上面course函数的返回数据
    Select(selenium.find_element_by_id("id_owner")).select_by_visible_text(user['username'])  # 选择作者
    Select(selenium.find_element_by_id("id_subject")).select_by_visible_text(course['category'])  # 选择主题
    selenium.find_element_by_id("id_title").send_keys(course['title'])  # 输入文章标题
    selenium.find_element_by_id("id_overview").send_keys(course['description'])  # 输入描述
    selenium.find_element_by_class_name("default").click()  # 点击保存


@then("页面中应存在名称为<标题>的链接")
def check_course(course):
    assert EC.presence_of_element_located(("link text", course['title']))


@then("删除该课程")
def delete_course(selenium, course):
    selenium.find_element_by_link_text(course['title']).click()
    selenium.find_element_by_class_name("deletelink").click()
    selenium.find_element_by_css_selector("input[type='submit']").click()


  • parsers用于解析语句中的参数
  • 方法中的selenium参数为使用pytest-selenium中的浏览器driver, 固定参数名
  • EC.presence_of_element_located用来验证可定位到元素

场景测试

# file_name: test_educa.py
from pytest_bdd import scenario
from scenario_steps import *  # 导入场景解释/支持步骤

@scenario("educa.feature", "通过educa后台添加课程")   
def test_add_course():  # 测试educa需求文件中名为"通过educa后台添加课程"的场景
    pass   # 可以不写内容, pass即可


  • 场景测试也可以和场景实现写到一起

执行测试

使用pytest-selenium执行用例是需要指定浏览器
在test_educa.py所在目录命令行中执行:

 pytest test_educa.py --driver Chrome

Pytest-bdd的参数化

待补充...

注: 上文提到BDD的初级使用,是因为这是一种被动的测试模式, 每一个不同的需求卡片的每一句都需要去进行解释实现, 其中有大量的重复性工作, 另外缺乏开发的参与与支持.
除了部分程度上, 消除测试同学需求理解的歧义性及让测试同学更注重用户场景的验证而不是开发(功能点)逻辑的验证外, 这基本上跟写selenium自动化脚本一样, 由于场景解释脚本的不稳定而耗费大量的工作无法发现有价值的问题

BDD行为驱动的最佳实践,请见下回分解...

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352

推荐阅读更多精彩内容