Руководство: Pyramid для Людей — часть 3

в 7:02, , рубрики: pyramid, python, tutorial for humans, перевод pyramid доки, метки: , ,

Часть 2: концепция, установка и простое «hello world» приложение

Шаг 02: юнит- и функциональное тестирование

Безусловно, тестирование помогает обеспечить будущее качество и облегчает рефакторинг. И это же, конечно, делает разработку более быстрой, в особенности при использовании умных редакторов и IDE. Перезапуск вашего приложения и щёлканье в вашем браузере это грустьпичаль(drag).


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

Цели
  • Покрыть код юнит-тестами
  • Создать функциональные тесты на ответы
Технические требования
  • Написать юнит-тест в Pyramid-стиле
  • Использовать WebTest, чтобы включить функциональный тест, в модуль тестов
  • Использовать nose и nosetests просмотрщик, для запуска тестов
Шаги

$ cd ../../creatingux; mkdir step02; cd step02
Создаем директорию в правильном месте.
Копируем нижеследующее, во вновь созданный файл step02/application.py:

from wsgiref.simple_server import make_server

from pyramid.config import Configurator
from pyramid.response import Response

def hello_world(request):
    return Response('hello!')

def main():
    config = Configurator()
    config.add_view(hello_world)
    app = config.make_wsgi_app()
    return app

if __name__ == '__main__':
    app = main()
    server = make_server('0.0.0.0'8080, app)
    server.serve_forever()

Это тот же самый код, который мы видели в шаге первом.
Копируем следующее в step02/tests.py:

import unittest

class ProjectorViewsUnitTests(unittest.TestCase):
    def test_hello_world(self):
        from application import hello_world
        result = hello_world({})
        self.assertEqual(result.body, 'hello!')

class ProjectorFunctionalTests(unittest.TestCase):
    def setUp(self):
        from application import main
        app = main()
        from webtest import TestApp
        self.testapp = TestApp(app)

    def test_it(self):
        res = self.testapp.get('/', status=200)
        self.failUnless('hello' in res.body)

$ nosetests
После этого мы должны увидеть следующий результат:
..
--------------------------------------------------------
Ran 2 tests in 0.301s

OK

Дополнительные вопросы
  • Как nose узнает, что тесты в файле tests.py?
  • Запускает ли WebTest реальный HTTP-сервер, чтобы послать HTTP-запрос?
  • Если ваш код выдает ошибку, обрабатывает ли Pyramid её корректно?
Анализ

Юнит-тесты это сложно. Юнит-тесты с фреймворком это ещё сложнее. Культура Pyramid, несмотря на это, нацелена на полное покрытие тестами, и Pyramid работает очень усердно, чтобы делать написание тестов полезным занятием.

Даже если вы не делаете полное покрытие тестами, вы обнаружите что большинство базовых юнит-тестов ловят стандартные ошибки быстрее чем открытие вашего браузера, для проверки, при каждом изменении кода. Это немного похоже на установку вашего редактора, или IDE, чтобы запустить pylint который позволяет вам знать до сохранения (намного меньше, перед выполнением) есть ли у вас ошибки.

Функциональные тесты проще к написанию, и для UX-людей, помогают в части рассматриваемой проблемы.

Тезисы
  • Pyramid (и repoze.bfg до неё) и верность тестовому покрытию
  • Философия юнит-тестирования против функциональных тестов, против док-тестов
  • The challenge in setup/teardown regarding configuration, registries, and machinery under the surface (both the frameworks and yours!)

Шаг 03: Hello World в Chameleon

Большинство веб-систем обладают языком шаблонов, для генерации HTML. Это дает UX-человеку возможность сконцентрироваться на вещи, которую они знают (разметка) и вкраплениями в коде, а не наоборот.

Pyramid doesn’t have too much of an opinion on templating languages. This tutorial does though. We’re Chameleon/ZPT folks. Так давайте же сделаем “hello world”, используя шаблон страницы.

Цели
  • Самый простой возможный шаг, чтобы понять про шаблон
Техническое задание
  • Передвинуть представление(views) в отдельный модуль
  • Поменять application.py, чтобы найти модуль, для объявления представлений
  • Продемонстрировать свежесть рендеринга и ориентированных на данные представлений, особенно для тестирования
  • Привести тесты к виду ориентированных на данные
Шаги

Вспомнить что в разделе установки сказано сделать $ export PYRAMID_RELOAD_TEMPLATES=1, что позволяет вам редактировать шаблоны и не иметь необходимостью перезагружать ваше Pyramid-приложение.
$ cd ../../creatingux; mkdir step03; cd step03
Копировать нижеследующее в step03/application.py:

from wsgiref.simple_server import make_server

from pyramid.config import Configurator

def main():
    config = Configurator()
    config.scan("views")
    app = config.make_wsgi_app()
    return app

if __name__ == '__main__':
    app = main()
    server = make_server('0.0.0.0'8080, app)
    server.serve_forever()

Копировать следующее в step03/views.py:

from pyramid.view import view_config

@view_config(renderer="hello.pt")
def hello_view(request):
    return {"tutorial""Little Dummy"}

И далее, уже разметку HTML-шаблона в step03/hello.pt:

<html>
<head>
    <title>Hello</title>
</head>
<body>
<p>Hello, ${tutorial}</p>
</body>
</html>

И вот это туда — step03/tests.py:

import unittest

class ProjectorViewsUnitTests(unittest.TestCase):
    def test_hello_view(self):
        from views import hello_view
        result = hello_view({})
        self.assertEqual(result['tutorial'], 'Little Dummy')

class ProjectorFunctionalTests(unittest.TestCase):
    def setUp(self):
        from application import main
        app = main()
        from webtest import TestApp
        self.testapp = TestApp(app)

    def test_it(self):
        res = self.testapp.get('/', status=200)
        self.failUnless('Hello' in res.body)

И последнее, пишем:
$ nosetests
Вслед за чем должны увидеть:
..
----------------------------------------------------------------
Ran 2 tests in 0.885s

OK

Пробуем запустить: $ python application.py
И открываем 127.0.0.1:8080 в своем браузере.

Дополнительные вопросы

Если вы редактируете тему, необходимо ли вам делать перезапуск приложения, чтобы увидеть изменения?
Какие другие значения возможны для рендерера, на @view_config?

Анализ

Этот шаг дает представление о разборе кода. Есть несколько различных путей чтобы сделать конфигурацию в Pyramid: императивный (который мы видели в первом шаге: Hello World в Pyramid), сканирующий (близкий ко многим современным веб-фреймворкам), и наш старый друг ZCML. The choice is mainly one of style, though there are some sharp edges in some cases.

Note the coolness… все что вам следует делать это вернуть словарь в ваше представление, и ваш шаблон вызывается on the way out the door, с этими данными.

Тезисы

История конфигурирования в Zope2, Zope3, BFG, потом Pyramid
How things worked before renderers

Следом идет часть 4.

Автор: ks_ks

Поделиться

* - обязательные к заполнению поля