Lettuce:Terrian

地形是一個Lettuce“雙關(guān)語”近迁,是它的“生活場所”,其安裝和拆卸,基本上嵌入在你的Lettuce測試垂睬。

terrain.py

按照慣例,Lettuce嘗試加載一個位于當前目錄下叫terrain.py的文件抗悍。
這個文件作為一個全局設(shè)置的地方驹饺,在那里你可以設(shè)置全局Hook,把事情放到Lettuce的“世界”缴渊。


你也可以將terrain.py文件設(shè)置在你的Django項目根目錄下赏壹,運行python manage.py命令時,Lettuce會加載它衔沼。更多內(nèi)容參考Django的命令蝌借。

實踐

嘗試下面的文件布局:

/home/user/projects/some-project
       | features
            - the-name-of-my-test.feature
            - the-file-which-holds-step-definitions.py
            - terrain.py

接著在terrian.py文件中加一些配置,運行Lettuce

user@machine:~/projects/some-project$ lettuce

注意terrian.py將首先加載

world

為了更容易和更有趣的編寫測試指蚁,Lettuce”違背了“python中好的設(shè)計的一些原則菩佑,如避免隱含的利用全局概念。
Lettuce的“world”概念主要是“全局的概念”欣舵。

實踐

想象一個位于某地的文件在Lettuce開始運行試驗之前擎鸠,被你的應(yīng)用程序?qū)耄?/p>

from lettuce import world

world.some_variable = "yay!"

因此,在一些步驟你可以使用world的預(yù)先設(shè)定文件:

from lettuce import *

@step(r'exemplify "world" by seeing that some variable contains "(.*)"')
def exemplify_world(step, value):
    assert world.some_variable == value

這個功能可能有點像:

Feature: test lettuce's world
  Scenario: check variable
    When I exemplify "world" by seeing that some variable contains "yay!"

world.absorb

將功能或類放入lettuce.world非常有用
例如:

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()

但是缘圈,正如你所注意到的劣光,隨著項目的發(fā)展,可能會有很多重復的行糟把,而起到避免代碼重復的:
為了避免這種情況绢涡,Lettuce提供給"world"一個“absorb”的修飾。
讓我們看下它:

from lettuce import world

@world.absorb
def my_project_wide_function():
    # do something

world.my_project_wide_function()

你也可以用類的形式使用它:

from lettuce import world

@world.absorb
class MyClass:
    pass

assert isinstance(world.MyClass(), MyClass)

甚至可以用Lambda表達式遣疯,但在這種情況下雄可,你需要命名它

from lettuce import world

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

assert world.optimist_function() == 'yeah'

world.spew

好吧,如果你讀了上面的內(nèi)容,你可能會想:“如果我要把一些事情放入lettuce.world数苫,有時候它可能膨脹聪舒,或迷惑與我的步驟,或hook的成員名虐急。
這種時候箱残,world“吸收”東西后,也可以“吐”止吁。

from lettuce import world

@world.absorb
def generic_function():
    # do something

assert hasattr(world, 'generic_function')

world.spew('generic_function')

assert not hasattr(world, 'generic_function')

Hooks

Lettuce有hook被辑,稱為順序之前和之后的每一個動作
作為Python的修飾,它可以采取任何對你有用的動作敬惦。
例如盼理,你可以設(shè)置一個瀏覽器驅(qū)動的world,以及最后關(guān)閉連接俄删,使用測試數(shù)據(jù)操作數(shù)據(jù)庫宏怔,或者其他任何你想做的,例如
讓我們由表及里的了解它

@before.all

這個hook將在Lettuce加載feature文件之前執(zhí)行
修飾函數(shù)不需要參數(shù)

from lettuce import *

@before.all
def say_hello():
    print "Hello there!"
    print "Lettuce will start to run tests right now..."

@after.all

這個hook將在Lettuce運行所有功能抗蠢,方案和步驟之后運行
修飾函數(shù)需要totalresult作為參數(shù)举哟,這樣你可以使用統(tǒng)計結(jié)果

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

這個hook是Lettuce運行每個功能前運行
修飾函數(shù)將Feature作為參數(shù),這樣你可以使用它來獲取場景和步驟迅矛。

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

這個hook和@before.each_feature一樣妨猩,除了:在Lettuce運行每個功能之后運行。

from lettuce import *

@after.each_feature
def teardown_some_feature(feature):
    print "The feature %r just has just ran" % feature.name

@before.each_scenario

這個hook是Lettuce運行每個場景之前運行
修飾函數(shù)將Senario作為參數(shù)秽褒,這樣你可以使用它來獲取內(nèi)部的步驟壶硅。

from lettuce import *
from fixtures import populate_test_database

@before.each_scenario
def setup_some_scenario(scenario):
    populate_test_database()

@after.each_scenario

這個hook和@before.each_scenario一樣,除了:在每個Scenario之后運行销斟。

from lettuce import *
from database import models
@after.each_scenario
def teardown_some_scenario(scenario):
    models.reset_all_data()

@before.each_outline

這個hook在Lettuce執(zhí)行每個場景大綱迭代前執(zhí)行
修飾函數(shù)將Scenario參數(shù)和輪廓庐椒,每一列的名稱是key

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"])

@after.each_outline

這個hook和@before.each_outline一樣,除了:在場景大綱迭代之后執(zhí)行蚂踊。

from lettuce import *

@after.each_outline
def complete_some_scenario(scenario, outline):
    print "We are now finished scenario {0} with size={1}".format(scenario.name, outline["size"])

@before.each_step

這個hook在Lettuce執(zhí)行每個步驟之前運行
修飾函數(shù)將Step作為參數(shù)约谈,這樣你可以用它獲取表

from lettuce import *

@before.each_step
def setup_some_step(step):
    print "running step %r, defined at %s" % (
        step.sentence,
        step.defined_at.file
    )

@after.each_step

這個hook和@before.each_step一樣,除了:在步驟執(zhí)行之后運行

from lettuce import *

@after.each_step
def teardown_some_step(step):
    if not step.hashes:
       print "no tables in the step"

django-specific hooks

自從Lettuce正式支持Django犁钟,有一些特定的hooks棱诱,幫助建立你的測試套件。

@before.harvest

這個hook是在Lettuce執(zhí)行Django試驗之前運行涝动。它可以設(shè)置瀏覽器的驅(qū)動程序迈勋,這是非常有用的(像selenium),在所有Django測試之前 醋粟。
修飾函數(shù)使用字典作為參數(shù)靡菇,內(nèi)嵌harvest命令行的局部變量重归。

from lettuce import *
from lettuce.django import django_url
from selenium import selenium

@before.harvest
def prepare_browser_driver(variables):
    if variables.get('run_server', False) is True:
        world.browser = selenium('localhost', 4444, '*firefox', django_url('/'))
        world.browser.start()

@after.harvest

這個hook是Lettuce執(zhí)行Django測試后運行。這非常有用厦凤,在關(guān)閉瀏覽器之前開始執(zhí)行(見上面的例子)鼻吮。
修飾函數(shù)用Totalresult對象列表作為參數(shù)。

from lettuce import *

@after.harvest
def shutdown_browser_driver(results):
   world.browser.stop()

@before.each_app

這個hook是在Lettuce運行每個Django程序之前運行泳唠。
修飾函數(shù)獲取與當前應(yīng)用程序相對應(yīng)的Python模塊狈网。

from lettuce import *

@before.each_app
def populate_blog_database(app):
    if app.__name__ == 'blog':
        from blog.models import Post
        Post.objects.create(title='Nice example', body='I like writting!')

@after.each_app

這個hook是在Lettuce運行每個Django程序之后運行。
修飾函數(shù)接受兩個參數(shù):
當前應(yīng)用相對應(yīng)的Python模塊笨腥。
Totalresult作為參數(shù),這樣你可以使用統(tǒng)計結(jié)果

from lettuce import *

@after.each_app
def clear_blog_database_if_successful(app, result):
    if app.__name__ == 'blog':
        if result.scenarios_ran is result.scenarios_passed:
            from blog.models import Post, Comment
            Comment.objects.all()
            Post.objects.all()

@before.runserver and @after.runserver

這些hooks是在Lettuce啟動內(nèi)置的HTTP服務(wù)器前后執(zhí)行勇垛。
修飾函數(shù)lettuce.django.server.threadedserver對象作為參數(shù)脖母。

from lettuce import *
from django.core.servers.basehttp import WSGIServer

@before.runserver
def prepare_database(server):
    assert isinstance(server, WSGIServer)
    import mydatabase
    mydatabase.prepare()

@after.runserver
def say_goodbye(server):
    assert isinstance(server, WSGIServer)
    print "goodbye, see you soon"

@before.handle_request and @after.handle_request

這些hooks是在Lettuce運行內(nèi)置HTTP請求前后運行。
修飾函數(shù)功能將下面兩個作為參數(shù):
django.core.servers.basehttp.wsgiserver對象闲孤。
lettuce.django.server.threadedserver對象

from lettuce import *
from django.core.servers.basehttp import WSGIServer

@before.handle_request
def print_request(httpd, server):
    socket_object, (client_address, size) = httpd.get_request()
    print socket_object.dup().recv(size)

@after.handle_request
def say_goodbye(httpd, server):
    socket_object, (client_address, size) = httpd.get_request()
    print "I've just finished to respond to the client %s" % client_address

警告
所有的handle_request hooks內(nèi)運行Python線程谆级。如果CalBack出錯,Lettuce會卡住讼积。


上一篇:Lettuce: Features, Scenarios and Steps reference
下一篇:Lettuce: Language Support

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末肥照,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子勤众,更是在濱河造成了極大的恐慌舆绎,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件们颜,死亡現(xiàn)場離奇詭異吕朵,居然都是意外死亡,警方通過查閱死者的電腦和手機窥突,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門努溃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人阻问,你說我怎么就攤上這事梧税。” “怎么了称近?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵第队,是天一觀的道長。 經(jīng)常有香客問我煌茬,道長斥铺,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任坛善,我火速辦了婚禮晾蜘,結(jié)果婚禮上邻眷,老公的妹妹穿的比我還像新娘。我一直安慰自己剔交,他們只是感情好肆饶,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著岖常,像睡著了一般驯镊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上竭鞍,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天板惑,我揣著相機與錄音,去河邊找鬼偎快。 笑死冯乘,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的晒夹。 我是一名探鬼主播裆馒,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼丐怯!你這毒婦竟也來了喷好?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤读跷,失蹤者是張志新(化名)和其女友劉穎梗搅,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體舔亭,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡些膨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了钦铺。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片订雾。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖矛洞,靈堂內(nèi)的尸體忽然破棺而出洼哎,到底是詐尸還是另有隱情,我是刑警寧澤沼本,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布噩峦,位于F島的核電站,受9級特大地震影響抽兆,放射性物質(zhì)發(fā)生泄漏识补。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一辫红、第九天 我趴在偏房一處隱蔽的房頂上張望凭涂。 院中可真熱鬧祝辣,春花似錦、人聲如沸切油。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽澎胡。三九已至孕荠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間攻谁,已是汗流浹背稚伍。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留巢株,地道東北人槐瑞。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像阁苞,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子祠挫,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容