行为驱动开发pytest-BDD
BDD
BDD 即 Behavior-driven development,行为驱动开发。
在软件工程中, BDD是一种敏捷开发流程。减少传统测试过程中由于技术背景能力,非技术与商业参与者之间业务理解不同而导致的问题。BDD它关注的核心是设计,其要求在设计测试用例的时候对系统进行定义,倡导使用通用的语言将系统的行为描述出来,将系统设计和测试用例结合起来,从而以此为驱动进行开发工作。
BDD行为驱动是一种敏捷开发模式, 重点在于消除开发/测试对需求了解的歧义及用户场景的验证.
pytest-BDD
https://pytest-bdd.readthedocs.io/en/latest/
BDD 使用自然语言Gherkin来描述系统功能和场景,根据这些描述步骤进行系统自动化的测试。
Pytest-bdd 是一个BDD测试框架,类似于behave, cucumber. 与许多其他传统框架pytest, unittest不同,BDD框架-pytest-bdd 不需要单独的运行程序,它可以统一单元测试和功能测试,减轻连续集成服务器配置的负担,并允许重用测试。
Pytest-bdd作为pytestde 一个插件,所有pytest的功能和插件都可以用于pytest-bdd!!
为单元测试编写的Pytest固定装置可以通过依赖项注入重新用于功能步骤中提到的设置和操作。允许对需求进行真正的BDD说明,而无需维护任何包含Gherkin命令性声明的上下文对象.
安装依赖
pip install pytest-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:一般用于验证结果(断言), 也可以进行清理数据
项目文件配置
按照下面所示,配置项目
└ -- tests
├ -- features
│ └ -- web.feature
└ -- step_defs
├ -- __init__.py
└ -- test_web_steps.py
代码预览
代码分析
gherkin语法
cucumber 可能是第一个行为驱动开发(Behavior-driven development)的自动化测试框架,它使用自然语言来描述测试,使得非程序员可以理解他们,其【feature】文件就是 gherkin 语法,不过是其子集而已
cucumber:黄瓜,gherkin:小黄瓜
pytest-bdd 是pytest的一个插件
Feature
介绍一下这个测试文件你要做什么
Feature:名字
描述内容
Scenario
描述一个场景
这里简单提一下测试用例,是为了某个特殊目标而编制的一组测试输入、执行条件以及预期结果,以便测试某个程序路径或核实是否满足某个特定需求。
在(Given我在输入框输入“深圳”)这句话中,我们可以注意到深圳被引用,就是跟gherkin说这里是测试用例的输入或者输出或者条件
引用这个语法其实是大家的约定,不是必须的
测试步骤
测试环境准备
@pytest.fixture
def browser(scope='session'):
# 启动浏览器
d = webdriver.Chrome(ChromeDriverManager().install())
# 隐式等待
d.implicitly_wait(10)
# 使用fixture 的代码将会在这部分执行
# 而且可以使用这个变量b
yield d
# 退出环境
d.quit()
这部分其实就是在每个测试开始前,启动浏览器,设置最多10s 的等待时间,测试结束即关闭浏览器
测试步骤对应feature文件
scenarios('../features/web.feature')
given
这步可以看成是测试步骤准备阶段,而且可以有返回值
注:其他的 when、then、and 等都不能放回值
这里的返回值值 when、then 等可以作为输入参数使用,参数名是此函数名,不是放回值的名字。
@given('我在输入框输入"深圳"')
def inputbox(browser):
# 访问网址
browser.get('https://www.baidu.com')
# 根据id查找元素
inputbox = browser.find_element_by_id('kw')
# 输入 深圳
inputbox.send_keys('深圳')
return inputbox
这一步首先访问目标网址,然后找到目标网址输入文字,最后返回输入框,以备后用
when、then、and
这些就是字面意思,写对应代码就行了,只不过and这步骤文件也写成then
@given('我在输入框输入"深圳"')
def inputbox(browser):
# 访问网址
browser.get('https://www.baidu.com')
# 根据id查找元素
inputbox = browser.find_element_by_id('kw')
# 输入 深圳
inputbox.send_keys('深圳')
return inputbox
@when('我点击"回车"')
def hit_enter(browser,inputbox):
inputbox.send_keys(Keys.RETURN)
@then('我可以在结果页面上看到"深圳野生动物园"')
def see_results(browser):
print('周到了then')
pass
feature举例
Feature: Multiple site support
Background:
Given a global administrator named "Greg"
And a blog named "Greg's anti-tax rants"
And a customer named "Wilson"
And a blog named "Expensive Therapy" owned by "Wilson"
Scenario: Wilson posts to his own blog
Given I am logged in as Wilson
When I try to post to "Expensive Therapy"
Then I should see "Your article was published."
Scenario: Greg posts to a client's blog
Given I am logged in as Greg
When I try to post to "Expensive Therapy"
Then I should see "Your article was published."
Scenario outlines写法
Feature: Scenario outlines
Scenario Outline: Outlined given, when, then
Given there are <start> cucumbers
When I eat <eat> cucumbers
Then I should have <left> cucumbers
Examples:
| start | eat | left |
| 12 | 5 | 7 |
| 10 | 6 | 5 |