地形是一個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