Lettuce:使用Lettuce和Django开发Web

Django是一个很棒的Web框架,非常成熟,并且很简洁。最大的好处是,使用上很有趣。为了让它更方便使用,lettuce已经内置支持它。

让我们开始

1. 安装Lettuce Django应用

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.admin',

    # ... other apps here ...
    'my_app',
    'foobar',
    'another_app',
    'lettuce.django', # this guy will do the job :)
)

假设我们想编写my_app Django应用的测试,请参考上面的配置。

2. 创建feature目录

Lettuce会去进入每一个已安装的app里找一个features目录:

/home/user/projects/djangoproject
     | settings.py
     | manage.py
     | urls.py
     | my_app
           | features
                - index.feature
                - index.py
     | foobar
           | features
                - carrots.feature
                - foobar-steps.py
     | another_app
           | features
                - first.feature
                - second.feature
                - many_steps.py

3. 编写你的第一个feature

@index.feature:

Feature: Rocking with lettuce and django

    Scenario: Simple Hello World
        Given I access the url "/"
        Then I see the header "Hello World"

    Scenario: Hello + capitalized name
        Given I access the url "/some-name"
        Then I see the header "Hello Some Name"

@index-steps.py:

from lettuce import *
from lxml import html
from django.test.client import Client
from nose.tools import assert_equals

@before.all
def set_browser():
    world.browser = Client()

@step(r'I access the url "(.*)"')
def access_url(step, url):
    response = world.browser.get(url)
    world.dom = html.fromstring(response.content)

@step(r'I see the header "(.*)"')
def see_header(step, text):
    header = world.dom.cssselect('h1')[0]
    assert header.text == text

4. 运行这个测试

一旦你安装lettuce.django这个应用,命令harvest就可用:

user@machine:~projects/djangoproject $ python manage.py harvest path/to/my-test.feature

启动Django服务前,harvest命令执行django.test.utils.setup_test_environment功能。通常,调用这个功能会使用locmen内存中邮箱去配置Django。然而,Lettuce使用自定义的Django邮箱去接收Lettuce测试脚本发送的邮件。细节,请参考“检查邮件”。

5. 识别feature文件

harvest命令允许使用文件路径,这样可以只执行你想执行的具体的features。
例子:

user@machine:~projects/djangoproject $ python manage.py harvest path/to/my-test.feature

6. 获取实际案例代码

为了确保lettuce很好的集成Django,提供了一系列的集成测试,有很多实际的Lettuce+Django项目。
你可以在lettuce Git仓库的alfaces目录下获取代码。

技术细节

如果你想使用web浏览器编写验收测试,你可以使用的工具有:twill, selenium, webdriver和windwill。

red-tape-less内置服务

Lettuce会智能地后台运行一个内置Gjango HTTP服务的实例。首先它会尝试将HTTP服务绑定在localhost:8000。但是如果这个端口被占用,它继续尝试运行在其他端口:8001,8002等等,直到尝试到最大的端口数65535。


你可以使用任何你想用的端口号替换默认端口“8000”。
为此,可以参考下面的“在8000以外的其他端口上运行HTTP服务器”。

如此你就可以使用上面列出的基于浏览器的工具来访问Django。

警告
当运行HTTP服务,lettuce设置环境变量SERVER_NAME和SERVER_PORT。它会导致一个GAE问题。如果它带来了任何错误,注意这个问题。

找出Django地址

因为Django HTTP服务能够使用8000到65535范围里面的任意端口运行,就比较难找出你项目确切的地址,对吧?
错!
你可以使用django_url功能定义到你的步骤中。

from lettuce import step, world
from lettuce.django import django_url

@step(r'Given I navigate to "(.*)"')
def navigate_to_url(step, url):
    full_url = django_url(url)
    world.browser.get(full_url)

django_url是如何工作的?

它附加了一个Django内部地址在HTTP服务地址上。
换句话说,如果lettuce绑定HTTP服务到localhost:9090,然后你使用“/admin/login”调用django_url:

from lettuce.django import django_url
django_url("/admin/login")

它会返回:

"http://localhost:9090/admin/login"

在django项目中,terrian也可用

你可能知道terrian.py怎么工作,它同样可以在Django项目中使用。
你可以在Django项目根路径下的terrian.py文件,设置环境和其他的配置。
以这个文档的第一个例子为例,你的Django项目目录结构如下:

/home/user/projects/djangoproject
     | settings.py
     | manage.py
     | urls.py
     | terrain.py
     | my_app
           | features
                - index.feature
                - index.py
     | foobar
           | features
                - carrots.feature
                - foobar-steps.py
     | another_app
           | features
                - first.feature
                - second.feature
                - many_steps.py

注意项目根路径下的terrain.py文件,你可以使用它填充和组织你的features和steps。

检查邮件

当你运行lettuce下的Django项目,邮件将不通过网络传输发送。而是被添加到对象lettuce.django.mail.queue。
例子:

from lettuce import step
from lettuce.django import mail
from nose.tools import assert_equals


@step(u'an email is sent to "([^"]*?)" with subject "([^"]*)"')
def email_sent(step, to, subject):
    message = mail.queue.get(True, timeout=5)
    assert_equals(message.subject, subject)
    assert_equals(message.recipients(), [to])

不使用HTTP服务执行

有时您可能不想后台运行Django内置HTTP服务器,在这些情况下,你需要做的就是使用--no-server或-S选项运行harvest命令。

python manage.py harvest --no-server
python manage.py harvest -S

在8000以外的其他端口上运行HTTP服务

如果Lettuce在端口8000上运行遇到问题,就可以改变这个端口。
在运行服务之前,Lettuce将尝试读取LETTUCE_SERVER_PORT,该设置必须为整数。
例子:

LETTUCE_SERVER_PORT = 7000

假如7000是你的默认开发端口,这将非常有用。

使用settings.DEBUG = True运行HTTP服务

为了使用最接近生产的配置运行测试,Lettuce设置settings.DEBUG=False。
但是,出于调试目的,在Django中如果不使用追踪,则可能会遇到误导性的HTTP 500错误。 对于这些场景,Lettuce提供--debug-mode或-d选项。

python manage.py harvest --debug-mode
python manage.py harvest -d

使用测试数据库

如果你想使用默认测试数据库,而不是在线数据库。在你的测试服务中,你可以使用-T标签,或者在setting.py中设置下面的配置变量。

LETTUCE_USE_TEST_DATABASE = True

只运行特定场景

你也可以通过命令指定你想运行的场景,为此,使用--scenarios或-s选项运行,后面跟上用逗号分隔的场景号。
例如,假设你要运行场景4、7、8和10:

python manage.py harvest --scenarios=4,7,8,10
python manage.py harvest -s 4,7,8,10v

运行或不运行,这是个问题!

在开发工作流程中,你可能会遇到两种情况:

从某些特定应用运行测试

Lettuce会以逗号分隔的应用名称列表来运行测试。
例如,下面的命令将仅在应用myapp和foobar中运行测试:

python manage.py harvest --apps=myapp,foobar

# or

python manage.py harvest --a  myapp,foobar

你也可以在settings.py中指定,这样就不必一直输入相同的命令行参数:

LETTUCE_APPS = (
    'myapp',
    'foobar',
)
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.admin',
    'my_app',
    'foobar',
    'another_app',
    'lettuce.django',
)

运行除了某些应用除外的所有测试

Lettuce运行使用逗号分隔的应用名称且没有标记NOT的列表。
例如,下面的命令将运行所有测试,但不包含another_app和foobar中的测试:

python manage.py harvest --avoid-apps=another_app,foobar

你也可以在settings.py中指定,这样就不必一直输入相同的命令行参数:

LETTUCE_AVOID_APPS = (
    'another_app',
    'foobar',
)

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.admin',
    'my_app',
    'foobar',
    'another_app',
    'lettuce.django',
)

上一篇:Lettuce:使用nose作断言
下一篇:结束,以上所有篇章暂时够用

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