关于lettuce的一个基本操作的总结

第一次完完整整的看完一个英文版文档,虽然字数不多,但对于我这样的菜鸟而言还是值得鼓励的。

Python BDD-lettuce

[总结于http://lettuce.it/]

Directory Structure:

|tests

  |features

    -zero.feature

    -steps.py

    -terrain.py

 

Scenarios:

There are two kinds of Scenarios:
1.Simple:

Feature: Apply all my friends to attend a conference

  In order to apply all my friends to the next PyCon_

  As a lazy person

  I want to fill the same form many times

 

  Scenario: Apply Mary

    Go to the conference website

    Access the link "I will attend"

    Fill the field "name" with "Mary"

    Fill the field "email" with "mary@domain.com"

    Fill the field "birthday" with "1988/02/10"

Click on "confirm attendance" button

 

2.Outlined:

Feature: Apply all my friends to attend a conference

  In order to apply all my friends to the next PyCon_

  As a lazy person

  I want to fill the same form many times

 

  Scenario Outline: Apply my friends

    Go to the conference website

    Access the link "I will attend"

    Fill the field "name" with "<friend_name>"

    Fill the field "email" with "<friend_email>"

    Fill the field "birthday" with "<friend_birthdate>"

    Click on "confirm attendance" button

 

  Examples:

    | friend_name | friend_email         | friend_birthdate |

    | Mary        | mary@domain.com      | 1988/02/10       |

    | Lincoln     | lincoln@provider.net | 1987/09/10       |

| Marcus      | marcus@other.org     | 1990/10/05       |

 

Steps:

Comparable with Scenarios,Steps comes in two kinds:

1.Simple:

Given I go to the conference website

 

2.Tabular:

Given I have the following contacts in my database

  | name  | phone      |

  | John  | 2233-4455  |

  | Smith | 9988-7766  |

 

Handling data with tables:

Example:

Feature:

  Scenario: Bill students which name starts with "G"

    Given I have the following students in my database:

      | name     | monthly_due | billed |

      | Anton    | $ 500       | no     |

      | Jack     | $ 400       | no     |

      | Gabriel  | $ 300       | no     |

      | Gloria   | $ 442.65    | no     |

      | Ken      | $ 907.86    | no     |

      | Leonard  | $ 742.84    | no     |

 

Steps:

@step(I have the following students in my database:)

Def test(step):

For t in step.hashes:

Person = Student(**student_dict)

Person.save()

 

Getting the first or the last row of the tables:

 

@step(I have the following students in my database:)

Def test(step):

Person1 = Student(**step.hashes.first)

Person2 = Student(**step.hashes.last)

Person1.save()

Person2.save()

 

Note:Every step has a attribute called hashes which is a list of dict.Each dict has represents table headers as keys and each table row as value.(table header : keytable row : value)

 

As follows:

 

@step(I have the following students in my database:)

Def test(step):assert step.hashes == [

        {

            'name': 'Anton',

            'monthly_due': '$ 500',

            'billed': 'no'

        },

        {

            'name': 'Jack',

            'monthly_due': '$ 400',

            'billed': 'no'

        },

        {

            'name': 'Gabriel',

            'monthly_due': '$ 300',

            'billed': 'no'

        },

        {

            'name': 'Gloria',

            'monthly_due': '$ 442.65',

            'billed': 'no'

        },

        {

            'name': 'Ken',

            'monthly_due': '$ 907.86',

            'billed': 'no'

        },

        {

            'name': 'Leonard',

            'monthly_due': '$ 742.84',

            'billed': 'no'

        },

    ]

 

Multi-line strings:

Can see : http://lettuce.it/tutorial/multiline.html

Calling steps from step definitions:

When we want to re-use steps that we’ve seen before,how we to do?

 

“step of steps”

@step('I am logged in')

def is_logged_in(step):

    step.given('I go to the home page')

    step.given('I click the login button')

 

“blocks of steps”

@step('I am logged in')

def is_logged_in(step):

    step.behave_as("""

        Given I go to the home page

          And I click the login button

          And I fill in username:{user} password:{pass}

          And I click "Login"

    """.format(user='floppy', pass='banana'))

 

The command line

Note: Lettue is used as a command line utility,it means that currently the only way to use it is through a shell.

Running a specific feature file:

Lettuce path/to/some/file.feature

 

Running only some scenarios of a specific feature file:

Lettuce path/to/some/file.feature -s 3,5,9

:this will run the scenarios 3,5 and 9 from the file

 

Verbosity level:

Lettuce --verbosity=1|2|3

Lettue -v 1|2|3

 

integrating with continuous integration(结合持续集成):

Lettuce can use Subunit to output test results.Subunit is a stream format that can be multiplexed(多路输出),viewed in real time or converted to many different formats(such as xUnit/jUnit XML format)

 

Lettuce --with-subunit > output.log

Subunit2junitxml<subunit.bin>lettucetests.xml

 

Coverage run lettuce --with-subunit

Coverage xml

 

Features,scenarios and steps reference

Can see : http://lettuce.it/reference/features.html

 

The “terrain”

Its about setup and teardown

By convention lettuce tries do load a file called terrain.py located at the current directory.

Think at this file as a global setup place,there you can setup global hooks,and put things into lettuce “world”

 

World:

To set the variable global

World.absorb:

To set the function/class global

As follows:

from lettuce import world

 

def my_project_wide_function():

    # do something

 

world.my_project_wide_function = my_project_wide_function

 

world.my_project_wide_function()

 

----->

 

from lettuce import world

 

@world.absorb

def my_project_wide_function():

    # do something

 

world.my_project_wide_function()

 

And even with lambdas,but in this case you need to name it:

 

from lettuce import world

 

world.absorb(lambda: "yeah", "optimist_function")

 

assert world.optimist_function() == 'yeah'

 

World.spew

Q:

If keep stashing things in lettuce.world,it may bloat it sometime, or confuse member names along my steps,or hooks.

A:

We can spew it.

from lettuce import world

 

@world.absorb

def generic_function():

    # do something

 

assert hasattr(world, 'generic_function')

 

world.spew('generic_function')

 

Hooks:

Lettuce has hooks that are called sequentially(有序调用) before and after each action

Presented as python decorators(装饰器)

 

@before.all

Note: this decorated function takes no parameters

from lettuce import *

 

@before.all

def say_hello():

    print "Hello there!"

    print "Lettuce will start to run tests right now..."

 

@after.all

Note: the decorated function takes a TotalResult as parameter

from lettuce import *

 

@after.all

def say_goodbye(total):

    print "Congratulations, %d of %d scenarios passed!" % (

        total.scenarios_ran,

        total.scenarios_passed

    )

    print "Goodbye!"

 

@before.each_feature

Note: the decorated function takes a Feature as parameter

from lettuce import *

 

@before.each_feature

def setup_some_feature(feature):

    print "Running the feature %r, at file %s" % (

        feature.name,

        feature.described_at.file

    )

 

@after.each_feature

The same as @before_feature

 

@before.each_scenario,@after.each_scenario

from lettuce import *

from fixtures import populate_test_database

 

@before.each_scenario | @after.each_scenario

def setup_some_scenario(scenario):

    populate_test_database()

 

@before.each_outline | @after.each_outline

Note: the parameter : ”outline” is the dictionary

from lettuce import *

 

@before.each_outline

def setup_some_scenario(scenario, outline):

    print "We are now going to run scenario {0} with size={1}".format(scenario.name, outline["size"])

 

@before.each_step

from lettuce import *

 

@before.each_step | @after.each_step

def setup_some_step(step):

    print "running step %r, defined at %s" % (

        step.sentence,

        step.defined_at.file

    )

 

Warning: all the handle_request hooks are run within a python thread. If something went wrong within a callback, lettuce can get stuck(被卡住).

 

我遇到的一些问题:

.feature文件中 Feature后必须紧跟一个空格,否则运行时会读取不到feature

 

在并不是很了解字典相关的时候,我自定义了一个方法作为字典的解析,如果仅仅是写一串{‘key1’:’value1’,‘key2’:’value2’,...}lettuce获取到并传递的时候,requests会报错400(传输数据的格式有误),虽然我尝试过,jsonpython中的格式其实也就是一个str,这点不是很理解。

def str_to_dict(str):
    temp_dict = {}
    temp_result = str.split(",")
    for key in temp_result:
        temp_key = key.split(":")
        temp_dict[temp_key[0].strip()]=temp_key[1].strip()
    return temp_dict

 

运行的时候基本遇到中文就是乱码,这方面资料网上少之甚少,最合理的一个解释就是别去使用dos运行,据说是可以使用eclipse去运行。没尝试过,但这种编码问题仅仅是影响到了我的输出结果,并不影响我的运行,所以也没有过多去关注。

posted @ 2016-12-06 13:33  北城以北花似海  阅读(1289)  评论(0编辑  收藏  举报