Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
This project contains extensions to test Tornado apps under pyvows.
branch: master

Merge pull request #17 from wking/loose-pyvows-dependency

setup.py: Loosen the pyVows dependency to blacklist bad versions
latest commit 28cc0b3995
Bernardo Heynemann heynemann authored

README.mkd

Build
Status

Tornado_pyVows

This project contains extensions to test Tornado apps under pyVows.

TornadoHTTPContext

To test a tornado app (or handlers) use this context instead of the regular Vows.Context, like this:

import tornado
from tornado_pyvows import TornadoHTTPContext
from pyvows import Vows, expect

class HomeHandler(tornado.web.RequestHandler):

    def get(self):
        self.write("hello_world")

    def post(self):
        self.write("hello_world")


@Vows.batch
class SomeVows(TornadoHTTPContext):

    def get_app(self):
        application = tornado.web.Application([
            (r"/", HomeHandler),
        ])
        return application

    class HomeUrl(TornadoHTTPContext):
        def topic(self):
            self.http_client.fetch(self.get_url('/'), self.stop)
            response = self.wait()
            return response.body

        def should_be_hello_world(self, topic):
            expect(topic).to_equal("hello_world")

    class SameUrl(HomeUrl):
        def topic(self):
            """
            For convenience you can also use ``get`` and ``post`` to wrap the 
            calls to the ``http_client``.
            """
            response = self.get("/")
            return response.body

    class SimplePost(HomeUrl):
        def topic(self):
            response = self.post("/")
            return response.body

Each TornadoHTTPContext provides Tornado's testing methods like http_client, get_url, stop, wait, fetch and others.

If you're developing based on Tornados HTTPClient you can just do that with simple wrappers as seen in client_vows.py

IsolatedTornadoHTTPContext

The new IsolatedTornadoHTTPContext creates a new HTTPServer that runs the application. This helps when testing handlers using mocks, e.g.::

@Vows.batch
class ASimpleTestWithAMock(TornadoHTTPContext):

    def get_handler_spec(self):
        """..."""
        return (r'^/echo$', ExampleHandler)

    def get_application_settings(self):
        return {'debug': True}

    class AndASimpleTestCase(IsolatedTornadoHTTPContext):

        def topic(self):
            mock = AsyncMock()
            mock.return_value = 'mocked echo'
            self.get_test_handler().echo = mock

            yield (mock, self.fetch('/echo'))

        def shouldWorkAsUsual(self, topic):
            expect(topic).Not.to_be_an_error()

        def shouldReturnTheExpectedTopic(self, topic):
            (_, resp) = topic
            expect(resp.body).to_equal('mocked echo')

        class ThatBlahsBlahs(TornadoHTTPContext):

            def topic(self, topic):
                yield (topic, self.fetch('/echo'))

            def shouldReturnTheExpectedTopic(self, topic):
                (_, resp) = topic
                expect(resp.body).to_equal('mocked echo')

    class ThatHasNoSideEffects(IsolatedTornadoHTTPContext):

        def topic(self):
            yield self.fetch('/echo')

        def shouldWorkAsUsual(self, topic):
            expect(topic).Not.to_be_an_error()

        def shouldReturnTheExpectedTopic(self, resp):
            expect(resp.body).to_equal('echo')

TornadoContext

If you want to test a tornado based app without the HTTP overhead you may also use the TornadoContext:

def asyncMethod(callback):
    callback("Pseudo Async Result")

@Vows.batch
class AsyncVows(TornadoContext):

    class CallbacksShouldWork(TornadoContext):

        def topic(self):
            self.io_loop = self.get_new_ioloop()
            self.io_loop.add_callback(lambda: asyncMethod(self.stop))
            return self.wait()

        def and_have_the_correct_result(self, topic):
            expect(topic).to_equal("Pseudo Async Result")

The above example creates a new IOLoop for every test, which is nice. Some libraries add callbacks to the IOLoop.instance() singleton, such as tornado.httpclient.AsyncHTTPClient. These libraries can be tested by overloading the get_new_ioloop method to return the IOLoop.instance() singleton.

@Vows.batch
class AsyncVows(TornadoContext):

    class PyVowsSiteVows(TornadoContext):

        def get_new_ioloop(self):
            return IOLoop.instance()

        def topic(self):
            self.io_loop = self.get_new_ioloop()
            http_client = AsyncHTTPClient()
            http_client.fetch("http://heynemann.github.com/pyvows/",
                              self.stop)
            return self.wait()

        def to_be_about_asynchronous_testing(self, topic):
            expect(topic.body).to_include('Asynchronous BDD for Python')

Contributors

Contributions are very welcome. To contribute fork it and create a pull request.

The team behind Tornado_pyVows (in order of joining the project):

Something went wrong with that request. Please try again.