Testing Mixins

Collection of functionality mix-ins.

This module contains standalone classes that can be safely mixed into the BaseTest class. Each mixin extends the functionality of the test case by adding behaviors, methods, and attributes - for example, patching well-understood functionality or automatically creating/destroying an in memory UDP server.

When creating a mixin it is important to take not that you should strive to keep the Method Resolution Order (MRO) as clean as possible. Each mixin class should ideally only inherit from object.

class test_helpers.mixins.EnvironmentMixin

Mix this class in if you manipulate environment variables.

A common problem in testing code that uses environment variables is forgetting that they are really globals that persist between tests. This mixin exposes methods that make it easy and safe to set and unset environment variables while ensuring that the environment will be restored when the test has completed.

You need to mix this in over a class that calls the configure annihilate class methods around the code under test such as test_helpers.bases.BaseTest.

classmethod annihilate()
classmethod configure()
classmethod set_environment_variable(name, value)

Set the value of an environment variable.

classmethod unset_environment_variable(name)

Clear an environment variable.

class test_helpers.mixins.PatchMixin

A mixin to allow inline patching and automatic un-patching.

This mixin adds one new method, create_patch that will create and activate patch objects without having to use the decorator.

In order to make use of the patching functionality you need to set the patch_prefix class attribute. This attribute should be the python module path whose objects you want to patch. For example, if you wanted to patch the baz object in the foo.bar module your patch prefix might look like foo.bar. When creating a patch you can now just refer to the object name like cls.create_patch('baz').

This usage of this mixin as opposed to the patch decorator results in less pylint errors and not having to think about the order of decorator application.

Example Usage:

class MyTest(mixins.PatchMixin, bases.BaseTest):

    patch_prefix = 'my_application.module.submodule'

    @classmethod
    def configure(cls):
        cls.foo_mock = cls.create_patch('foo')
        cls.bar_mock = cls.create_patch('bar', return_value=100)

    @classmethod
    def execute(cls):
        function_under_test()

    def should_call_foo(self):
        self.foo_mock.assert_called_once_with()

    def should_return_100_from_bar(self):
        self.assertEqual(100, self.bar_mock.return_value)
classmethod create_patch(target, **kwargs)

Create and apply a patch.

This method calls mock.patch() with the keyword parameters and returns the running patch. This approach has the benefit of applying a patch without scoping the patched code which, in turn, lets you apply patches without having to override setUpClass() to do it.

Parameters:target (str) – the target of the patch. This is passed as an argument to cls.patch_prefix.format() to create the fully-qualified patch target.
patch_prefix = ''
classmethod setUpClass()
classmethod stop_patches()

Stop any active patches when the class is finished.

classmethod tearDownClass()

Tornado Specific Helpers

class test_helpers.mixins.tornado.JsonMixin

Mix in over TornadoMixin to enable JSON handling.

This mix in extends TornadoMixin.request() so that it will automatically serialize request data and deserialize responses as JSON. It does honor the HTTP content type headers so it will not accidentally deserialize a non-JSON response or serialize an already serialized request.

classmethod request(*args, **kwargs)

Send a request and process the response.

Parameters:
  • args – positional parameters to send to super().request
  • kwargs – keyword parameters to send to super().request
Returns:

either a tornado.httpclient.HTTPResponse instance or None if the request timed out.

class test_helpers.mixins.tornado.TornadoMixin

Test tornado applications with AAA testing.

Mix this class in over test_helpers.bases.BaseTest or similar classmethod-based testing class and you can directly test tornado-based applications.

Usage

from unittest import TestCase
import test_helpers.mixins.tornado
import myproject

class WhenMyApplicationsGets(mixins.tornado.TornadoMixin, TestCase):

    @classmethod
    def setUpClass(cls):
        super(WhenMyApplicationGets, cls).setUpClass()
        cls.start_tornado(myproject.Application())
        cls.execute()

    @classmethod
    def tearDownClass(cls):
        super(WhenMyApplicationGets, cls).tearDownClass()
        cls.stop_tornado()

    @classmethod
    def execute(cls):
        cls.response = cls.get('/index')

    def should_return_ok(self):
        self.assertEqual(self.response.code, 200)

Attributes

This mix-in creates three useful attributes in addition to the methods. Each of the attributes is initialized by start_tornado() and will be None until that method is called.

client

The tornado.httpclient.HTTPClient instance used to interact with the application.

io_loop

The tornado.ioloop.IOLoop instance that the application is attached to.

url_root

The URL root used to interact with the application. This refers to host and port that io_loop is attached to.

request_timeout

The number of seconds to run the IO loop for before giving up on the request.

classmethod delete(path, **kwargs)

Issue a DELETE request.

classmethod get(path, **kwargs)

Issue a GET request.

classmethod head(path, **kwargs)

Issue a HEAD request.

classmethod options(path, **kwargs)

Issue a OPTIONS request.

classmethod patch(path, body, **kwargs)

Issue a PATCH request.

classmethod post(path, body, **kwargs)

Issue a POST request.

classmethod put(path, body, **kwargs)

Issue a PUT request.

classmethod request(method, path, **kwargs)

Issue a request to the application.

Parameters:
  • method (str) – HTTP method to invoke
  • path (str) – possibly absolute path of the resource to invoke
  • kwargs – additional arguments passed to the tornado.httpclient.HTTPRequest initializer
Returns:

either a tornado.httpclient.HTTPResponse instance or None if the request timed out.

The path parameter can be a relative path or an absolute URL. It will be joined to url_root before the request object is created.

classmethod start_tornado(application)

Start up tornado and register application.

Parameters:application – anything suitable as a Tornado request callback (see tornado.httpserver.HTTPServer)

This method binds a socket to an arbitrary temporary port, creates a new Tornado IOLoop, and adds the application‘ to it. Calling any of the request-related methods will start the IOLoop and run it until a response is received.

classmethod stop_tornado()

Terminate the tornado IO loop.

class test_helpers.mixins.tornado.TornadoTest(methodName='runTest')

Tornado version of BaseTest.

This class acts as a replacement for BaseTest with the Tornado magic pre-mixed. All that you have to do is:

  1. set tornado_application as a top-level class attribute OR
  2. pass the application keyword to configure() and make sure that this class is the first one in the __mro__

In either case, the application is the Tornado request callback that is being tested. See tornado.httpserver.HTTPServer for a complete description of what constitutes a “request callback”.

classmethod annihilate()

Terminates the Tornado application.

classmethod configure(application=None)

Configures the Tornado IOLoop.

Parameters:application – overrides tornado_application
tornado_application = None

The Tornado request handler callable.