Guide: Pyramid for People - Part 3

    Part 2: concept, installation and simple hello world application

    Step 02: Unit and Functional Testing

    Of course, testing helps ensure future quality and facilitates refactoring. And this, of course, makes development faster, especially when using smart editors and IDEs . Restarting your application and clicking in your browser is a drag.

    This step uses the same code as the first step, but we will add some tests.

    Goals
    • Coat code with unit tests
    • Create functional tests for answers
    Technical requirements
    • Write a pyramid-style unit test
    • Use WebTest to include a functional test in the test module
    • Use nose and nosetests viewer to run tests
    Steps

    $ cd ../../creatingux; mkdir step02; cd step02
    Create a directory in the right place.
    Copy the following into the newly created file 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 ()
    This is the same code that we saw in step one.
    Copy the following into 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
    After that, we should see the following result:
    ..
    --------------------------------------------------------
    Ran 2 tests in 0.301s

    OK


    Additional questions
    • How does nose know what tests are in tests.py?
    • Does WebTest start a real HTTP server to send an HTTP request?
    • If your code throws an error, does Pyramid handle it correctly?
    Analysis

    Unit tests are difficult. Unit tests with the framework are even more complicated. The Pyramid culture, however, aims to be fully covered by tests, and Pyramid works very hard to make writing tests a useful activity.

    Even if you do not do full test coverage, you will find that most basic unit tests catch standard errors faster than opening your browser to check for code changes every time. This is a bit like installing your editor, or IDE, to run pylint which lets you know before saving (much less before executing) if you have any errors.

    Functional tests are easier to write, and for UX people, they help in the part of the problem under consideration.

    Abstracts
    • Pyramid (and repoze.bfg before it) and fidelity to test coverage
    • Unit testing philosophy against functional tests, against dock tests
    • The challenge in setup / teardown regarding configuration, registries, and machinery under the surface (both the frameworks and yours!)
    Step 03: Hello World in Chameleon

    Most web systems have a template language for generating HTML. This gives the UX-man the opportunity to concentrate on the thing that they know (markup) and interspersed in the code, and not vice versa.

    Pyramid doesn't have too much of an opinion on templating languages. This tutorial does though. We're Chameleon / ZPT folks. So let's make “hello world” using the page template.

    Goals
    • The easiest possible step to understand about the template.
    Technical task
    • Move a view to a separate module
    • Change application.py to find the module to declare views
    • Demonstrate the freshness of rendering and data-oriented views, especially for testing
    • Bring tests to data-oriented
    Steps

    Recall that the installation section tells you to do this $ export PYRAMID_RELOAD_TEMPLATES=1, which allows you to edit templates and not have to restart your Pyramid application.
    $ cd ../../creatingux; mkdir step03; cd step03
    Copy the following to 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 ()
    Copy the following to step03/views.py:
    from  pyramid.view  import  view_config

    @view_config (renderer = "hello.pt")
    def  hello_view (request):
        return  {"tutorial": "Little Dummy"}
    And further, the markup of the HTML template is already in step03/hello.pt:


        </strong>Hello<strong>


    Hello, $ {tutorial}




    And here it is - 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)
    And finally, we write:
    $ nosetests
    After what we should see: Try to run: And open in your browser.
    ..
    ----------------------------------------------------------------
    Ran 2 tests in 0.885s

    OK


    $ python application.py
    127.0.0.1:8080

    Additional questions

    If you are editing a theme, do you need to restart the application to see the changes?
    What other values ​​are possible for the renderer on @view_config?

    Analysis

    This step provides insight into code parsing. There are several different ways to make configuration in Pyramid: imperative (which we saw in the first step: Hello World in Pyramid), crawling (close to many modern web frameworks), and our old friend ZCML. The choice is mainly one of style, though there are some sharp edges in some cases.

    Note the coolness ... all you have to do is return the dictionary to your view, and your template is called on the way out the door, with this data.

    Abstracts

    History of configuration in Zope2, Zope3, BFG, then Pyramid
    How things worked before renderers

    Next comes part 4 .

    Also popular now: