官方 github

https://github.com/pytest-dev/pytest-bdd

官方文档

https://pytest-bdd.readthedocs.io/en/latest/

安装

  1. pip install pytest-bdd

快速入门小栗子

quick.feature

创建一个 quick.feature文件

  1. Feature: Blog
  2. A site where you can publish your articles.
  3. Scenario: Publishing the article
  4. Given I'm an author user
  5. And I have an article
  6. When I go to the article page
  7. And I press the publish button
  8. Then I should not see the error message
  9. And the article should be published

test_quick.py

创建一个 test_quick.py文件

  1. import pytest
  2. from pytest_bdd import scenario, given, when, then
  3. # pytest fixture
  4. # use for the following step
  5. @pytest.fixture
  6. def auth():
  7. return dict()
  8. @pytest.fixture
  9. def author():
  10. return dict(user={"name": "polo", "age": 24})
  11. # given step
  12. @given("I'm an author user")
  13. def author_user(auth, author: dict):
  14. auth['user'] = author['user']
  15. print("=== auth is ", auth)
  16. # second given step
  17. @given("I have an article", target_fixture="article")
  18. def article(author):
  19. print("=== fixture article: author is ", author)
  20. return author
  21. # when
  22. @when("I go to the article page")
  23. def go_to_article(article):
  24. print("=== go to article ", article)
  25. @when("I press the publish button")
  26. def publish_article():
  27. print("=== opeate: press publish button")
  28. # then
  29. @then("I should not see the error message")
  30. def no_error_message():
  31. print("=== expect: should not see the error message")
  32. assert 1 == 1
  33. @then("the article should be published")
  34. def article_is_published(article):
  35. print("=== expect: the article should be published")
  36. assert article == dict(user={"name": "polo", "age": 24})
  37. # scenario
  38. @scenario('quick.feature', 'Publishing the article')
  39. def test_publish():
  40. pass

pytest 运行

在上述两个文件所在目录下,命令行敲

  1. pytest -sq test_quick.py

运行结果

  1. === auth is {'user': {'name': 'polo', 'age': 24}}
  2. === fixture article: author is {'user': {'name': 'polo', 'age': 24}}
  3. === go to article {'user': {'name': 'polo', 'age': 24}}
  4. === opeate: press publish button
  5. === expect: should not see the error message
  6. === expect: the article should be published
  7. .
  8. 1 passed in 0.01s

来拆解知识点了

@scenario

这是场景装饰器,会在最后执行,扒源码

  1. def scenario(feature_name: str, scenario_name: str, encoding: str = "utf-8", features_base_dir=None):
  2. """Scenario decorator.
  3. :param str feature_name: Feature file name. Absolute or relative to the configured feature base path.
  4. :param str scenario_name: Scenario name.
  5. :param str encoding: Feature file encoding.
  6. """

前两个位置参数必传,参数解析也很明白了

  • feature_name:feature 文件的名,绝对/相对于设置的 feature base path 路径
  • scenario_name:在 feature 文件中的 Scenario 关键字后面跟的字符串,场景名称�

假设不写这个装饰器会怎么样

  1. # scenario
  2. # @scenario('quick.feature', 'Publishing the article')
  3. # def test_publish():
  4. # pass

再次运行 pytest 命令

  1. pytest -sq test_quick.py

运行结果

  1. > pytest -sq test_quick.py
  2. no tests ran in 0.00s

没有识别到对应的测试用例

feature 文件的拆解

重要的几个基础关键字

这里用中文来描述一个具体的🌰

  1. Feature: 需求标题,官方网址 - 登录功能
  2. 下面是对官方网址 - 登录功能进行设计多个测试场景
  3. 以下的描述,可以由非测试人员编写:FeatureScenarioGivenWhenAndThen
  4. 通过特定的关键字 + 自然语言,来描述一个用户的操作行为
  5. Scenario: 场景1 - 正常登录
  6. # Given 数据定义,可以只有一个;如果要有多个,需要用 And 关键字
  7. Given 正常登录的用户,用户名:admin 密码:123456
  8. And 这个登录用户的详细信息,性别:女,年龄:24
  9. # When 测试具体的步骤
  10. When 打开登录页面
  11. And 输入用户名
  12. And 输入密码
  13. And 点击登录按钮
  14. # Then 进行判断
  15. Then 登录成功,判断页面链接是否为跳登录跳转后页面的链接
  16. And 验证用户名是否一致
  17. Scenario: 场景2 - 登录失败
  18. ...
  • Feature:需求背景,一般第一行写一个需求标题,后面几行可以写需求具体的描述;一个 feature 只能有一个 Feature 关键字
  • Scenario:测试场景,一个 feature 文件可以有多个场景 Scenario,区分名字即可
  • �Given:前置操作,一般用来做预置条件/准备数据,如果有多个可以换行使用 And 关键字
  • And:表示当前关键字作用域未结束
  • When:具体的操作/测试步骤
  • Then:后置操作,一般用来验证结果(断言),数据清理等操作

整体的流程可以简单看成

Given - When - Then
准备 - 执行 - 验证

基础讲完了,后面逐一拆解官方文档