测试自动化_博客已迁移测试员的那点事自动化测试

python behave学习笔记 - feature tes

2017-10-20  本文已影响72人  做测试的DanteYu

Feature Testing Layout

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

一个可执行的最小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 -v (-v verbose)可以看到更详细的behave行为

Gherkin: Feature Testing Language

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

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

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

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

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的好实践:

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都会占据一行。并且以下面五个关键字中的一个来开头:

通常来讲这些关键字都应该是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,

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

在命令行中tag的用法:

tags与environment.py的互动

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()
上一篇下一篇

猜你喜欢

热点阅读