Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

BDD-разработка на django

Anna | 15.06.2014 | нет комментариев
Программисты дюже по различному относятся к тестированию, и многие не любят писать тесты. Процесс TDD же для новичков не исключительно внятен — чай доводится взамен функционала программы писать сначала тест, тот, что его проверяет, то есть число работы возрастает. Впрочем со временем приходит осознание того, что механическое тестирование нужно. К примеру, возьмем процесс разработки даже несложного плана на django, пока в плане пара вьюх и моделек все легко. Когда приложение обрастает функциями, неожиданно обнаруживается, что делать такое тестирование все труднее — кликов огромнее, нужно вносить какие-то данные и т.д., вот здесь-то и на поддержка приходит behavior-driven development (BDD).

image

Я хочу рассказать о BDD на примере создания примитивного приложения — рейтинга сайтов. Идея банальна — на странице отображается список сайтов, пользователь голосует за сайт, сайт подымается в рейтинге и соответственно изменяет расположение на странице.

Для начала в рабочей папке плана создаем requirements.txt, с приблизительно таким оглавлением:

Django
git git://github.com/svfat/django-behave
splinter

Обратите внимание, в разработке я использую свой форк django-behave. Код из официального репозитария отказался трудиться, видимо по причине несовместимости с нынешними версиями программ.

$ pip install -r requirements.txt
$ django-admin.py startproject habratest
$ cd habratest/
$ ./manage.py startapp vote

По умолчанию должна установиться последняя стабильная версия Django, и для начала разработки нам понадобится добавить лишь несколько строчек в settings.py:

INSTALLED_APPS = (
    ...
    'vote',
    'django_behave',
)
TEMPLATE_DIRS = (
    os.path.join(BASE_DIR, 'templates/'), # не забываем сделать папку habratest/templates
)
TEST_RUNNER = 'django_behave.runner.DjangoBehaveTestSuiteRunner'

Первым этапом добьемся отображения списка сайтов. Для разработки в BDD-жанре с поддержкой имеющихся у нас инструментов, создаем папки habratest/vote/features и habratest/vote/features/steps

Тут мы будем описывать поведение, которого мы хотим добиться от приложения. В папке features создаем файл habra.features с таким содержимым:

Feature: Habrarating

  Scenario: Show a rating
    Given I am a visitor
    When I visit url "http://localhost:8081/"
    Then I should see link contents url "habrahabr.ru"

Не дюже схоже на компьютерный язык, да? Это — Gherkin. На нем дозволено описать поведение программы не вдаваясь в реализацию. Таким образом, писать тестовые задания может человек немного приятель с программированием.

Мы указываем такой URL, потому что django-behave запускает тестовый сервер на порте 8081.

В той же папке создаем environment.py, код в котором выполняется до и позже тестирования, и пока только обеспечивает работоспособность тестового браузера:

from splinter.browser import Browser

def before_all(context):
    context.browser = Browser()

def after_all(context):
    context.browser.quit()
    context.browser = None

Запускаем

$ ./manage.py test vote

Ничего не получилось — тестовое окружение не понимает, что делать с шагами в файле habra.features.Видите строки желтого (ну либо каштаново-желтого) цвета? Отважно копируйте их в habratest/vote/features/steps/habra.feature.py, в нем описывается реализация шагов, и его оглавление должно стать приблизительно таким:

from behave import given, when, then

@then(u'I should see link contents url "{content}"')
def i_should_see_link_contents_url(context, content):
    msg = context.browser.find_link_by_partial_href(content).first
    assert msg

@when(r'I visit url "{url}"')
def i_visit_url(context, url):
    br = context.browser
    br.visit(url)

@given(u'I am a visitor')
def i_am_a_visitor(context):
    pass

Запускаем еще раз

 $ ./manage.py test vote

Так, сейчас мы обязаны видеть что наш тест фейлится, и повод очевидна — мы еще не написали ни строчки кода функционала приложения, да и данных в базе нет.

Создаем модельку в vote/models.py

class VoteItem(models.Model):
    url = models.URLField()
    rating = models.IntegerField(default=0)

    class Meta:
        # это для того Дабы в ListView наши сайты сортировались по рейтингу
        ordering = ["-rating"]

    def __unicode__(self):
        return self.url

Делаем:

$ ./manage.py syncdb

В habratest/urls.py импортируем

from vote.views import VoteListView

и добавляем в urlpatterns

    url(r'^$', VoteListView.as_view(), name="index"), 

в vote/views.py

from django.views.generic import ListView
from models import VoteItem

class VoteListView(ListView):
    model=VoteItem
    template_name="list.html"

в habratest/templates/list.html наш образец в жанре ретро:

<!DOCTYPE html>
<html>
    <head>
        <title>Habra rating</title>
    </head>
    <body>
        <ol>
            {% for voteitem in object_list %}
            <li id="{{voteitem.pk}}"><a href="{{ voteitem.url }}">{{ voteitem.url }}</a>
            | Rating:{{voteitem.rating}}</li>
            {% endfor %}
        </ul>
    </body>
</html>

При запуске тестов в памяти всякий раз создается новая БД, а позже окончания удаляется, следственно ее нам необходимо заполнить какими-то данными. Для это в файл habratest/habratest/populate.py пишем:

from vote.models import VoteItem

VoteItem(url="http://www.yandex.ru", rating=6).save()
VoteItem(url="http://www.google.com", rating=5).save()
VoteItem(url="http://www.habrahabr.ru", rating=6).save()

и дописываем импорт этого скрипта в environment.py

from habratest import populate

Сейчас environment.py помимо обеспечения работы браузера еще и занимается тестовой базой.

Вновь запускаем

$ ./manage.py test vote 

— чудесно, тест пройден.Но как же рейтинг — нам нужно чай как-то голосовать за сайты

Добавляем новейший сценарий в habra.feature:

  Scenario: Vote for a site
    Given I am a visitor
    When I visit url "http://localhost:8081/"
    When I click link contents " "
    Then I should see "Vote successful" somewhere in page

Тестовое окружение не знает как исполнить два последних шага, следственно дописываем их в steps/habra.feature.py:

@then(u'I should see "{text}" somewhere in page')
def i_should_see_text_somwhere_in_page(context, text):
    assert text in context.browser.html

@when(u'I click link contents "{text}"')
def i_click_link_contents_text(context, text):
    link = context.browser.find_link_by_text(text).first
    assert link
    link.click()

Позже чего вновь запускаем тесты. Оплошность на шаге When I click link contents ” “. Так — никакой ссылки ” ” у нас в образце нет, как и не предусмотрена реакция на нее, что мы и поправим дальнейшим образом (не обращайте внимание, что код никак не защищен от накрутки, это каждого лишь иллюстрация):

В habratest/templates/list.html добавляем «плюс»:

<li id="{{voteitem.pk}}"><a href="{{ voteitem.url }}">{{ voteitem.url }}</a>
             | Rating:{{voteitem.rating}}
             | <a href={% url 'addvote' voteitem.pk %}> <a></li>

Соответственно создаем простую вьюшку для addvote в vote/views.py:

from django.shortcuts import render_to_response

def addvote(request, pk):
    return render_to_response('successful.html', context)

добавляем ее в urls.py,

from vote.views import VoteListView, addvote

и

    url(r'^plus/(?P<pk>d )/$', addvote, name='addvote'),

И образец templates/successful.html:

<!DOCTYPE html>
<html>
    <head>
        <title>Habra rating</title>
    </head>
    <body>
        <p>Vote successful</p>
    </body>
</html>

Запускаем тесты — все должно пройти удачно.

А сейчас напишем тест для проверки работоспособности увеличения рейтинга. Мы обязаны увидеть метаморфозы в списке при голосовании, тут воспользуемся тем, что знаем начальные данные (которые внесли в populate.py), так как y habrahabr.ru rating=6, при клике на ” ” его рейтинг должен измениться на единицу, и по выполнению предыдущего сценария, его рейтинг должен стать равным «7».

  Scenario: Vote for a site and look at the rating
    Given I am a visitor
    When I visit url "http://localhost:8081/"
    Then I should see "Rating:7" somewhere in page

Вновь конечный шаг не выполняется. Для того, Дабы поправить это, дописываем вьюшку addvote:

def addvote(request, pk):
    item = VoteItem.objects.get(pk=pk)
    item.rating  = 1
    item.save()
    return render_to_response('successful.html')

Проверяем, сейчас тест проходит удачно.

Выходит, продолжая писать тесты на gherkin (что, как я теснее говорил выше, может делать даже человек не приятель с программированием) мы реально сделаем часть технического задания и, единовременно, приемочного тестирования нашего приложения.

Я написал эту статью, так как на русском языке фактически нет информации по BDD с django, и, если ее внезапно будут читать эксперты в этом вопросе, не поленитесь, напишите в комментариях о своей практике. Это будет благотворно каждому. С радостью приму ваши примечания, исправления и критику. Спасибо!

Что еще почитать:
Behave documentation
Splinter — test framework for web applications
Django Full Stack Testing and BDD with Lettuce and Splinter

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB