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作断言
下一篇:结束,以上所有篇章暂时够用

你可能感兴趣的:(Lettuce:使用Lettuce和Django开发Web)