python behave学习笔记 - feature testing

Feature Testing Layout

要让behave工作起来需要下面三种类型的文件

  • 由非技术人员 BA/Sponsor等编写的 feature files , 这些文件包含着应用的场景行为
  • 一个 step 目录。这个目录下面包含着scenario对应的测试代码
  • environmental control文件。这个是optional的
    • environment.py里面包含着关于run before after steps scenarios features等testing hook代码

一个可执行的最小feature目录为

features/
features/everything.feature
features/steps/
features/steps/steps.py

最小为一个features目录下面一个feature文件和一个steps目录。steps里面包含了测试代码。

一个更复杂的目录为

features/
features/signup.feature
features/login.feature
features/account_details.feature
features/environment.py
features/steps/
features/steps/website.py
features/steps/utils.py

behave命令执行

behave是灵活的,我们通过执行带有不同选项的命令来帮助behave找到feature文件,然后来执行指定的文件

  • 当执行behave 时, behave会从当前目录下寻找”features”子目录,然后从中读取feature文件
  • 当执行behave ./features,给behave传递features目录所在路径,behave会从中读取至少一个 name.feature 文件和一个叫 steps 的目录。对于environment.py, 如果有的话,必须是和 steps 目录在同一个目录下
  • 当执行behave ./features/BookInformationAPITest.feature 给behave传递了一个指定的feature file,behave就会执行指定的这个feature
  • 也可以给behave传递a directory containing your feature files。 behave的工作方式和上述方法类似

behave -v (-v verbose)可以看到更详细的behave行为

Gherkin: Feature Testing Language

behave的features文件是由一种叫Gherkin的语言编写的并且被命名为 name.feature

在理想情况下,这些feature files是有项目内的非技术人员比如需求方使用自然语言来编写。feature files有两个目的,一个是作为正式文档 ,二是支持自动化测试

feature files的编写非常自由灵活,但是还是有一些好的准则可以坚持:

  • 行结尾终止声明
  • spaces或tabs都可以作为缩进
  • 缩进都会被忽略,但是缩进是一个用来展示文本结构的好办法
  • 大部分的行要以关键字为开头。Keywords: Feature, Scenario, Given

在文件的任何地方都可以使用 “#”来进行注释

Features

Features是由Scenarios来组成。Feature还可以加上description,background和tag,不过这些都是可选的。

最简单的feature形式为

Feature: feature name

  Scenario: some scenario
      Given some condition
       Then some result is expected.

把description background tag都加上后,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.

Feature name应该为待测feature的合理描述的标题

description

description是optional的,可以用来澄清任何潜在的confusions或是scope issue

Background

background是由一些step组成,这些step和scenarios里面的一样。Background允许你给feature中的scenario加一些context。Background的执行是在feature文件中所有的scenario之前,不过是在所有before hooks之后。

一个feature文件只有一个background。ackground必须在scenario或是scenario outline之前定义好。background经常被用来做一些setup的事情,比如登陆一个页面或是设置好数据库

使用background的好实践:

  • 不要用”Background’来设置较为复杂的状态除非客户要求
  • 保持”Background”短小精炼。如果Background大于4行,我们就可以把一些无关的细节挪到high level的steps
  • 使得“Background”栩栩如生,通俗易懂。可以使用丰富的名称和描述来讲述一个故事。
  • 保持scenario不会很长,也不能太多。不然Background会执行很多遍

Scenarios

Scenarios描述了需要测试的产品行为。Scenario是由一系列steps组成。这些steps典型的形式是”given some condition” “then we expect some test will pass"

scenario最简单的形式为

Scenario: we have some stock when we open the store
  Given that the store has just opened
  Then we should have items for sale.

如果有需要的话,and或是but都可以加到scenario里面,放在given when then之后

Scenario: Replaced items should be returned to stock
  Given that a customer buys a blue garment
    and I have two blue garments in stock
    but I have no red garments in stock
    and three black garments in stock.
   When he returns the garment for a replacement in black,
   then I should have three blue garments in stock
    and no red garments in stock,
    and two black garments in stock.

一个比较好的实践是一个scenario就测试一个行为或是一种desired outcome

Scenario Outlines

当对于同一个场景有着很多不同的期待输入条件和输出结果,我们可以使用scenario outline来做数据驱动,这样可以重用scenario中的step

一个outline包含定义在step中的关键字,这些关键字会被表格中的数据来代替。一个scenario outline可以有多个example tables

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 |

behave会跑example table里面的每一行。每一行的数据会去替代step里面尖括号定义的<thing> <other thing>

注意尖括号里的名字必须和表格头的名字一致。

python step implementation如下

from behave   import given, when, then
from hamcrest import assert_that, equal_to
from blender  import Blender

@given('I put "{thing}" in a blender')
def step_given_put_thing_into_blender(context, thing):
    context.blender = Blender()
    context.blender.add(thing)

@when('I switch the blender on')
def step_when_switch_blender_on(context):
    context.blender.switch_on()

@then('it should transform into "{other_thing}"')
def step_then_should_transform_into(context, other_thing):
    assert_that(context.blender.result, equal_to(other_thing))

把<thing>作为参数传入方法里面

Steps

每个step都会占据一行。并且以下面五个关键字中的一个来开头:

  • given
  • when
  • then
  • and
  • but

通常来讲这些关键字都应该是Title Case就是首字母大写的形式,部分语言还是支持只有全小写

step的描述不应该包含太多关于测试机制的细节

比如下面

Given a browser client is used to load the URL "http://website.example/website/home.html"

就应该变为

Given we are looking at the home page

Steps的实现是由python写的测试代码组成,python的模块“name.py”会被放在”steps”文件夹下。python模块的文件命名是没有规定的。所有在”steps”下面的文件都会被behave引入

Given

givens的目的是在用户或外部系统对系统进行交互之前,使系统处于一个可知的状态。在givens中要避免涉及用户交互的操作。
在use case中,givens可以被理解为前置条件precondition。也可以在Given中使用table来设置一些数据

When

whens的目的是描述用户或是外部系统施展的关键行为。这个交互行为会引起系统状态的变化

Then

thens的目的是观察结果。这个观察的结果应该与feature描述的用户价值business value/benefit相关联。这个结果也应该是一个系统产生的

具体的结果而不是对用户不可见,埋藏得很深的结果。对用户不可见的结果也许会没有business value。比如我们应该多验证用户看得见的结果而不是去数据库里面找结果

我们还可以使用And But来组织steps

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

可以写为

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

这两种写法对behave都是一样的

Step Data

Steps除了given when then,还允许包含像文本text和表格table样的数据。所以一个step可以包含自己的texttable,这就是Step Data

Scenario Outline values的一个替代方法就是使用<name>在Step data text或是table中

Text

任何在step中使用三个双引号包括的文本就是Step data中的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

注意非第一行的whitespace数不能比第一行少。

在测试代码中,我们使用Context.text来获取这段text。Context.text也可以在每一个step function中传递使用。

第一个step定义的text是可以在scenario后面的step中的context中使用。在候选step中定义的text会overwrite之前step中的text。

Table

我们可以把一个表格数据赋予给一个step,只需要通过简单的输入,缩进即可。当我们想把一系列的数据赋值给一个model
的时候,这个Table特别有用

整个表格有两个 vertical bar “|“ 来区别列。任何在列和vertical bar之间的whitespace会被删除

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"

在测试代码中,我们使用Context.table来获取这段table。Context.table也可以在每一个step function中传递使用。测试代码中,我们使用如下

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

Tags

feature file中可以使用tag功能。tag功能可以让behave实现选择性的执行feature

tag可以作用于feature,scenario和scenario outline。作用于feature的tag也会作用于feature下的scenario或scenario outlines

tag使用修饰符的样式作用于feature/scenario/scenario outlines,多个tag之间可以使用whitespace来进行间隔

For example:

@wip @slow
Feature: annual reporting
  Some description of a slow reporting system.

or

@wip
@slow
Feature: annual reporting
  Some description of a slow reporting system.

Controlling Your Test Run With Tags 我们可以使用tag来选择性的执行测试
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

对于上面这个feature file,

  • 如果运行 behave —tags=slow 就只会运行标记了slow的Scenario Weaker opponent
  • 如果运行 behave —tags=-slow,就会运行没有标记slow的Scenarios

一个常用的场景是使用@wip来处理正在开发中的scenario或feature,使用behave —tags=wip来运行这个正在开发的feature

在命令行中tag的用法:

  • 如果我们执行behave —tags=slow,slow1 只要被tag为slow或slow1的scenario被执行
  • 如果我们执行behave —tags=slow —tags=slow1 只要被tag为slow并且slow1的scenario被执行

tags与environment.py的互动

  • 如果一个feature或是scenario被skip了,那么相应的before_和after_都不会执行
  • environment.py中各方法中的feature/scenario对象都有tags属性,这个属性是列出了所有tag名称的列表
  • environment.py中的before_tag和after_tag。如果这两个方法被传入了”slow”,那么在执行被tag为slow的scenario之前,这两个方法会被调用

for example,部分scenario被tag为@browser,则我们可以使用feature.tags来查看tag有没有browser.这样做,我们可以指定哪些feature需要执行这个before_和after_

def before_feature(context, feature):
    model.init(environment='test')
    if 'browser' in feature.tags:
        context.server = simple_server.WSGIServer(('', 8000))
        context.server.set_app(web_app.main(environment='test'))
        context.thread = threading.Thread(target=context.server.serve_forever)
        context.thread.start()
        context.browser = webdriver.Chrome()

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

推荐阅读更多精彩内容

  • 基本概念 behave要被执行,需要运行在满足下面两种情况的目录下 有feature files。这个featur...
    做测试的DanteYu阅读 16,072评论 0 7
  • 从某种意义上来看,世间一切,都是遇见。就像, 冷遇见暖,就有了雨; 春遇见冬, 有了岁月; 天遇 见地, 有了永恒...
    相约遇见阅读 144评论 0 0
  • 大脑程序使用说明书 微信号 how13355789267 欢迎加好友交流 暗号:商学院 跨年夜智商程序装上了,但使...
    精英之门阅读 420评论 1 4
  • 我的公众号是转角遇到更好的自己,我也曾对我朋友说过,我感觉我的生命从30岁才刚刚开始,30岁之前太过懵懂,不知道自...
    转角遇到最好的自己阅读 191评论 0 0
  • 学习财商第二天,感触自己的人生过的太无知啦!而为无知付出的代价就是活到了现在这个模样!财商的学习刻不容缓!而且,孩...
    莫有青草阅读 138评论 0 0