behave是python语言的行为驱动开发,全称:Behavior-driven development,简称BDD。

BDD框架

BDD即行为驱动开发(Behavior Driven Development),其特点为:

  • 通过自然语言来定义系统行为
  • 从功能使用者的角度,编写需求场景
  • 鼓励软件项目中的开发者、非技术人员以及商业参与者之间的协作。协作的核心是通过活文档或者说场景文档来协作,该文档既是测试用例文档,也是需求定义文档
  • 常见的BDD框架有Behave,Cucumber等

它是一种敏捷软件开发技术,它鼓励软件项目中的开发人员、QA和非技术或业务参与者之间进行协作。

python behave的官方网址:

https://behave.readthedocs.io/en/latest/gherkin.html#gherkin-feature-testing-language

最初由Dan North命名,并于2009年对BDD给出了如下定义:
“BDD是第二代、由外而内、基于拉动、多利益相关者、多规模、高度自动化、敏捷的方法。

它描述了一个与定义明确的输出交互的循环,从而交付了重要的工作、测试软件。”

BDD并不会描述或定义软件怎么做,而是能做了什么。最终通过python代码进行验证。

首先用pycharm创建项目Python-Behave,python环境选择Virtualenv,接着安装behave包。

在项目Python-Behave下创建一个名为“features”的目录(这个目录名称是随意的),可以在这个目录下定义所有behave的文件结构。

在features目录下创建一个“.feature”文件,这是一种叫作“Gherkin”的语言。它对非技术人员比较友好,可以使用自然语言编写。

“.feature”文件有两个用途:文档和自动化测试。一句话,在“.feature”里编写测试场景。

很多文章提到Gherkin语言必须用pycharm专业版才能编写,但是我亲测用pycharm社区版也是可以编写的。

“.feature”文件的结构:

主体由多个场景Scenario组成,可以选用Background和tag进行约束。

feature文件的一个基本的结构为:

Feature: feature name

  Scenario: some scenario
    Given some condition
     When some operation
     Then some result is expected  
  • Feature是功能名称
  • Scenario是场景描述
  • Given是此场景下的前提条件
  • When是此场景下的操作步骤
  • Then是此场景下的预期结果

如果有多个测试场景呢,就再加一个Scenario。如果Scenario下的Given/When/Then有多个呢?

可以用And或But表示。

所以

Scenario: Multiple Givens
  Given one thing
  Given another thing
  Given yet another thing
   When I open my eyes
   Then I see something
   Then I don't see something else  

也可以这样写作

Scenario: Multiple Givens
  Given one thing
    And another thing
    And yet another thing
   When I open my eyes
   Then I see something
    But I don't see something else  

这种方式阅读会更流畅

当然,上面只是一个简单的feature结构,更复杂一点的,比如说这样:

@tags @tag
Feature: feature name
  description
  further description

  Background: some requirement of this test
    Given some setup condition
      And some other setup action

  Scenario: some scenario
      Given some condition
       When some action is taken
       Then some result is expected.

  Scenario: some other scenario
      Given some other condition
       When some action is taken
       Then some other result is expected.

  Scenario: ...  

Background由一系列类似于Scenario的步骤组成,它的目的是为Scenario添加上下文,在Scenario执行之前执行Background,用于设置Scenario的前提条件。

Scenario由一系列步骤组成,它描述了Feature的一种场景。如果一种场景有多种情况呢?

比如登录这个Scenario,不同的登录名和密码,登录的结果不同。这种情况可以不需要写多个Scenario描述,可以使用Scenario Outline和Examples来完成。

Scenario Outline: Blenders
   Given I put <thing> in a blender,
    when I switch the blender on
    then it should transform into <other thing>

 Examples: Amphibians
   | thing         | other thing |
   | Red Tree Frog | mush        |

 Examples: Consumer Electronics
   | thing         | other thing |
   | iPhone        | toxic waste |
   | Galaxy Nexus  | toxic waste |  

在上面这个例子中,用Scenario Outline描述“Blenders”场景,用多个Examples表示场景的多种类型,每个Examples下可以包含多种情况。不同情况的列举在Scenario Outline用符号“<key>”表示,在Examples中用key列举

Scenario由一系列步骤组成,步骤由关键字“Given”、“When”、“Then”、“And”、“But”为开头。Python Behave实际运行的也是这些步骤。

具体实现是通过此项目下的steps目录里的“.py”文件实现所有的Scenario的步骤。这里要注意,steps目录名是确定的不能改变的,但是里面的py文件名是随意的。

python behave项目的执行方式也并不是通过运行steps目录里的py文件,而是通过命名behave调用“.feature”文件,映射到py文件里的步骤下的函数,执行这些函数。

步骤描述要尽量简洁,但有时会附带一些文本text或表格table。如果python代码需要使用这些text或table,则可以通过访问属性“context.text”或”context.table“来使用。

Text:

Scenario: some scenario
  Given a sample text loaded into the frobulator
     """
     Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
     eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
     enim ad minim veniam, quis nostrud exercitation ullamco laboris
     nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
     reprehenderit in voluptate velit esse cillum dolore eu fugiat
     nulla pariatur. Excepteur sint occaecat cupidatat non proident,
     sunt in culpa qui officia deserunt mollit anim id est laborum.
     """
 When we activate the frobulator
 Then we will find it similar to English  

Table:

 Scenario: some scenario
  Given a set of specific users
     | name      | department  |
     | Barry     | Beer Cans   |
     | Pudey     | Silly Walks |
     | Two-Lumps | Silly Walks |

 When we count the number of people in each department
 Then we will find two people in "Silly Walks"
  But we will find one person in "Beer Cans"  

Python中访问:

@given('a set of specific users')
def step_impl(context):
    for row in context.table:
        model.add_user(name=row['name'], department=row['department'])  

这个表格在python中是这样的数据类型:

[{"name":"Barry", "department":"Beer Cans"},{"name":"Pudey", "department":"Silly Walks"},{"name":"Two-Lumps", "department":"Silly Walks"}]  

认真体会下!!!

Tags:

tags用于标记Feature、Scenario或Scenario Outlook,可以选择性的只执行被标记的。

例如:

Feature: Fight or flight
  In order to increase the ninja survival rate,
  As a ninja commander
  I want my ninjas to decide whether to take on an
  opponent based on their skill levels

@slow
Scenario: Weaker opponent
  Given the ninja has a third level black-belt
  When attacked by a samurai
  Then the ninja should engage the opponent

Scenario: Stronger opponent
  Given the ninja has a third level black-belt
  When attacked by Chuck Norris
  Then the ninja should run for his life  

如果只想执行Scenario: Weaker opponent,可以对它进行标记为@slow,然后运行“behave --tags=slow”。

如果想执行除标记@slow外的其他场景,可以运行“behave --tags=“not slow””。

组合使用tags标签:

–tags=“wip or slow”,选择所有标记为wip或slow的case

–tags=“wip and slow”,选择所有标记为wip和slow的case

以上讲的是如何用“.feature”文件编写所有测试场景。虽然是通过命令behave xxx.feature触发,但实际的执行操作是在steps目录下的“.py”实现。

所以,要如何把“.feature”里的所有步骤映射到“.py”中,还必须按照顺序不能出错,这就成为了一个关键。

假设给定一个Senario:

Scenario: Search for an account
   Given I search for a valid account
    Then I will see the account details  

记住,只对所有的步骤按顺序实现,并不会对Scenario进行映射。

在python中实现如下:

@given('I search for a valid account')
def step_impl(context):
    context.browser.get('http://localhost:8000/index')
    form = get_element(context.browser, tag='form')
    get_element(form, name="msisdn").send_keys('61415551234')
    form.submit()

@then('I will see the account details')
def step_impl(context):
    elements = find_elements(context.browser, id='no-account')
    eq_(elements, [], 'account not found')
    h = get_element(context.browser, id='account-head')
    ok_(h.text.startswith("Account 61415551234"),
        'Heading %r has wrong text' % h.text)  

按照“.feature”中的步骤的顺序,将步骤的前面的关键字,在python中用装饰器匹配(@give、@when、@then),()里面是步骤描述。

如果是And或But,在python中用它们被重命名以前的关键字。也就是说,在python中,不可能有@and或@but。

然后在装饰器下方定义函数,函数名随意。函数体就是步骤的具体实现。

如果你想在某个步骤里执行另一个步骤,只需要用context对象调用execute_steps()函数,里面传入被调用步骤。

@when('I do the same thing as before')
def step_impl(context):
    context.execute_steps('''
        when I press the big red button
         and I duck
    ''')  

如果你想把“.feature”的步骤上的信息传递到“.py”中,可以在py文件中用中括号加关键字表示“{key}”。

比如访问百度首页:

Scenario: 访问百度网页
    Given: 打开网页
    When: 输入网址www.baidu.com
    Then:显示百度首页  

关于其中输入百度网址,在python中就可以这样实现:

@when(输入网址{baidu})
def step_imp1(context, baidu):
    context.driver.get(baidu)  

Context:

聪明的你一定注意到了,在py文件中每个步骤下的函数内第一个参数是context,它是Feature或Scenario的实例化,可以用来传递信息。

如何传递呢,这里我们暂且按下不表,先思考一个问题。

如果我有一个场景,打开百度网页,输入关键字搜索,然后查看搜索结果。

在feature文件中如何描述,这个我们应该已经学会了。在py文件中如何实现,我们也不陌生了。

Scenario: 打开百度网页并输入关键字
    Given: 打开百度网页http://www.baidu.com
    When: 输入关键字大美女
    Then:验证返回的搜索结果标题是大美女_百度搜索  
@given(打开百度网页{baidu})
def step_imp1(context, baidu):
    context.driver.get(baidu)  

@when(输入关键字{keyword})
def step_imp1(context, keyword):
    context.driver.find_element_by_xpath('//*[@id="kw"]').send_keys(keyword)
    ...  

后面我就不写了。现在只看given的步骤,你应该就能发现问题,context.driver哪来的,从已知的上下文中并没有相关信息。

如果你再仔细的思考一下,就会发现这里少了一步,我们在打开百度网站前,是不是应该先打开浏览器,然后才是输入百度网址。

如果你有多个关于网页搜索的场景,你是不是应该每次执行Scenario前都要打开浏览器,执行完毕关闭浏览器。这个操作类似于python unittester中的setup()和teardown()的用法。

那python behave框架中,对于操作前和操作后的前置条件和后置条件,是放在了“environment.py”文件中定义。

它有以下几种:

  • before_step(context, step)和after_step(context, step),每一步之前和之后运行
  • before_scenario(context, scenario)和after_scenario(context, scenario),每个场景运行之前和之后运行
  • before_feature(context, feature)和after_feature(context, feature),每个feature文件执行之前和之后运行
  • before_tag(context, tag)和after_tag(context, tag),每个标签调用之前和之后运行
  • before_all(context)和after_all(context),整个behave之前和之后运行

那上面的例子中,在environment.py中实现打开和关闭浏览器的操作,要这样实现:

# environment.py
from selenium import webdriver

def before_scenario(context, scenario):
    context.driver = webdriver.Chrome(r"/usr/local/bin/chromedriver")

def after_scenario(context, scenario):
    context.driver.close()  

前置条件和后置条件在environment.py中用上面列举的函数直接定义,函数名和形参必须符合规范。

可以看出,如果environment.py中的信息、变量或对象需要在steps中的py文件中被使用,可以用context来存储。

这里就把打开的浏览器对象赋值给了context下定义的driver属性,然后在py文件中直接可以使用context.driver,就相当于使用这个浏览器了。

注意注意,environment.py文件在python behave项目中的位置是哪里?是steps目录中吗?

不是的,environment.py文件是和“.feature”文件、steps目录并列在同一目录下的。而且它的名称必须是environment.py。

现在回头看下一个完整的python behave项目的最低结构要求:

 --features/
|    --steps/       # -- Steps directory
|   |     -- *.py   # -- Step implementation or use step-library python files.
|    -- *.feature   # -- Feature files.  

更复杂的目录为:

 -- features/
|      -- steps/
|     |     -- website_steps.py
|     |     -- utils.py
|     |
|      -- environment.py      # -- Environment file with behave hooks, etc.
|      -- signup.feature
|      -- login.feature
|      -- account_details.feature  

最后,如何执行behave的程序?

不是执行的steps目录里的py文件,而是通过cmd打开命令行窗口,执行:“behave xxx.feature”。

这样也很麻烦,有没有一种方式可以在py文件的主入口里执行"behave xxx.feature",这样可以封装成exe程序,双击运行exe,即可运行behave。

在python behave项目目录下创建一个py文件(也就是和feature文件、steps目录文件在同一级下),命名为main.py,然后写一个主入口程序:

# main.py
from behave.__main__ import main as behave_main
import os

if __name__ == "__main__":
    # 获取main.py的当前目录
    featurefile_dir = os.path.dirname(os.path.realpath(__file__))
    # 获取feature文件的绝对路径
    featurefile_path = os.path.join(featurefile_dir, "Behave.feature")
    # 用behave.__main__下的main函数,传入feature文件路径,实现behave xxx.feature相同的效果
    # 但是这里有个主要点,传入feature文件的路径不能是以这样“\”或这样“\\”的表示方式,必须要改成这种“/”
    featurefile_path = featurefile_path.replace("\\", "/")
    behave_main(featurefile_path)
    # 或者你不转成“\”,那么你就不能直接传入feature文件路径了,必须把文件路径放入一个list中,然后把list传入
    # 如果你传入list,相当于传入多个参数,这时候除了文件路径,还可以传入tags参数,以执行标记的功能或场景
    cmd_order = []
    cmd_order.append(featurefile_path) # 把feature文件路径添加为list的第一个元素
    cmd_order.append("-t @slow") # 把tag标签添加为list的第二个元素
    behave_main(cmd_order) # 传入参数列表  

到此这篇关于Python Behave框架学习的文章就介绍到这了,更多相关Python Behave框架内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

Python Behave框架学习的更多相关文章

  1. xcode6.1 – Xcode 6.1中项目模板中缺少类前缀

    项目模板上曾经有一个类前缀字段,这有助于区分项目类和框架类.Xcode6.1项目模板中不再提供此功能.这背后的意图是什么?

  2. ios – 伞框架

    错误.应用程序,通常位于…错误仍然存在你也可以在这里添加(子)框架的路径.

  3. ios – UIView框架大小的问题

    我正在开发一个iPad项目,目前正在使用Landscape视图.我试着这样做:为什么这总是返回960?虽然在景观中,视图本身的高度尺寸应为768对吗?

  4. 安装自定义cocoa框架的最佳方法

    我有一个自定义框架,遵循Apple的框架编程指南>>中的建议.Installingyourframework我在/Library/Frameworks中安装.我通过使用以下脚本添加RunScript构建阶段来完成此操作:在我的项目中,我然后链接/Library/Frameworks/MyFramework并将其导入我的类中,如下所示:这非常有效,除了我总是在调试器控制台中看到以下消息:Loadin

  5. ios – 在设备上构建和运行时,仅将嵌入式框架与其他动态框架链接失败

    TL;博士将您的嵌入式框架与其他框架链接,并且不将其他框架与您的应用程序链接,导致Build&在设备上运行.描述:建立:我的设置非常简单(Swift2.3&XcodeXcode8.0;Build版本8S162m):>使用Carthage(0.17.2)我用xcodebuild8.0和TOOLCHAINS=com.apple.dt.toolchain.Swift_2_3carthagebui

  6. iOS 8嵌入式框架中的头文件

    我正在尝试创建一个用于iOS8的嵌入式框架.在创建一个名为SampleKit(BTW;这里有任何约定,我应该使用前缀吗?)之后,它包含一个令我困惑的头文件:我知道FOUNDATION_EXPORT是extern或extern“C”的宏,但我不确定这两个常量.我应该在哪里为他们设定价值?解决方法项目>构建设置>版本控制>当前项目版本:

  7. 在Monotouch上模拟.NET的框架?

    有没有人使用过他们发现与Monotouch兼容的.NET模拟框架?在尝试使用之前,我很好奇与NMock,NSubstitute,Moq和其他框架的兼容性.Xamarin刚刚加强了它的单元测试支持,但没有提到模拟框架.仅供参考,我希望在VS2010上为非UI位做很多开发,并在UI进入时移动到iOS平台.谢谢您的帮助.解决方法我建议只使用手动模拟:如果我不得不猜测RhinoMocks,Moq等大量使用Reflection.Emit(你怎么能做他们能做的疯狂?),这将无法在MonoTouch上使用AOT编译器运

  8. 在ios上使用来自框架的boost :: filesysystem路径

    我一直在使用Boost作为PeteGoodliffe脚本构建的框架已有一段时间了.效果很好.最近我遇到了一个问题,可以通过将以下代码放入另一个全新的XCode项目中的视图控制器的viewDidLoad中来重现:当路径对象被销毁时会导致EXC_BAD_ACCESS.有没有其他人遇到这个问题?

  9. ios – 在约束依赖于框架的自定义视图中使用自动布局

    我正在编写一个以编程方式初始化的自定义视图.我重写updateConstraints以添加此视图所需的所有约束.:问题是self.bounds返回CGRectZero的等价物.我做了我的研究并根据这个objc.ioarticle,这是预期的,因为在调用layoutSubviews之前框架不会被设置.它也提到了Toforcethesystemtoupdatethelayoutofaviewtreei

  10. ios – “禁用模块时使用’@import’”错误 – 启用模块和链接框架= YES

    我有一个使用CocoaPods并使用’SCLAlertView-Objective-C’窗格的项目.该pod使用@importUIKit;模块样式导入.我在目标和项目设置中将“启用模块(C&Objective-C)”和“自动链接框架”设置为YES.当模块被禁用时,我仍然得到“使用’@import’错误.有没有什么可以阻止Xcode能够启用模块,如使用.pch文件,任何链接器标志,或者我没有提到的任

随机推荐

  1. 10 个Python中Pip的使用技巧分享

    众所周知,pip 可以安装、更新、卸载 Python 的第三方库,非常方便。本文小编为大家总结了Python中Pip的使用技巧,需要的可以参考一下

  2. python数学建模之三大模型与十大常用算法详情

    这篇文章主要介绍了python数学建模之三大模型与十大常用算法详情,文章围绕主题展开详细的内容介绍,具有一定的参考价值,感想取得小伙伴可以参考一下

  3. Python爬取奶茶店数据分析哪家最好喝以及性价比

    这篇文章主要介绍了用Python告诉你奶茶哪家最好喝性价比最高,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧

  4. 使用pyinstaller打包.exe文件的详细教程

    PyInstaller是一个跨平台的Python应用打包工具,能够把 Python 脚本及其所在的 Python 解释器打包成可执行文件,下面这篇文章主要给大家介绍了关于使用pyinstaller打包.exe文件的相关资料,需要的朋友可以参考下

  5. 基于Python实现射击小游戏的制作

    这篇文章主要介绍了如何利用Python制作一个自己专属的第一人称射击小游戏,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起动手试一试

  6. Python list append方法之给列表追加元素

    这篇文章主要介绍了Python list append方法如何给列表追加元素,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  7. Pytest+Request+Allure+Jenkins实现接口自动化

    这篇文章介绍了Pytest+Request+Allure+Jenkins实现接口自动化的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  8. 利用python实现简单的情感分析实例教程

    商品评论挖掘、电影推荐、股市预测……情感分析大有用武之地,下面这篇文章主要给大家介绍了关于利用python实现简单的情感分析的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下

  9. 利用Python上传日志并监控告警的方法详解

    这篇文章将详细为大家介绍如何通过阿里云日志服务搭建一套通过Python上传日志、配置日志告警的监控服务,感兴趣的小伙伴可以了解一下

  10. Pycharm中运行程序在Python console中执行,不是直接Run问题

    这篇文章主要介绍了Pycharm中运行程序在Python console中执行,不是直接Run问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

返回
顶部