Package: kt.testing
Applications that make use of large frameworks often need to mock or
stub out portions of those APIs in ways that provide a consistent view
on the resources that API exposes.  A test fixture often wants to
establish a particular state for the API at a higher level than that of
individual API calls; this is especially the case if an API provides
more than one way to do things.  How the code under test uses the
underlying API is less interesting than the information exposed by the
API and the operations performed on it.There are a number of ways to approach these situations using tests
based onunittest.TestCasefixtures.  Too often, these
become tangled messes where test authors have to pay attention to
implementation details of base and mix-in classes to avoid support for
different APIs interfering with each other’s internal state.This library approaches the problem by allowing APIs that support test
control of other frameworks or libraries to be independent components.
Thesefixture componentscan:access the test object,be involved in setup and teardown,provide cleanup handlers,provide APIs for tests to configure the behavior of the APIs they
manage, andprovide additional assertion methods specific to what they do.These components can inject themselves into the APIs they manage in
whatever ways are appropriate (usingmock.patch, for example).Release history3.1.2 (2018-12-19)Minor tweak:AssertionErrorraised bykt.testing.requestsfixture when
there is no prepared response now provides a more substantial message
for PATCH, POST, and PUT requests, showing more information about the
payload.  This can make it easier to debug problems.3.1.1 (2018-10-19)Bug fixed:Packaging:  Wheels are not universal since we don’t want to depend onmockunder Python 3.3.1.0 (2018-10-19)New feature:kt.testing.cleanupsupports global registration of cleanup
functions called before & after every test (when usingkt.testing.TestCase).  Directly inspired byzope.testing.cleanup, and cooperative with the same.Development support:Add tox configuration for running tests.3.0.0 (2017-11-30)Backward incompatible change:Thektnamespace package is switched to use apkgutil-style
construction, removing thepkg_resourcessupport entirely.  This
should not affect many users.SeePackaging namespace packagesfor more information about
namespace package styles.2.2.0 (2017-09-29)New feature:kt.testing.requestsresponse objects support theiter_contentmethod, so long asdecode_unicodeis false.2.1.0 (2017-09-05)New feature:kt.testing.requestsintercepts therequestsAPI at a slightly
lower level, hooking into the underlyingrequests.sessions.Sessionobject instead ofrequests.api.requests.  This makes it possible
to use this with packages that manage their own session objects, or
even derived session objects, as long as therequestmethod is not
overridden.2.0.0 (2017-06-19)WarningThis release isnotbackward compatible with prior releases.
Testsmustnow be derived from thekt.testing.TestCaseclass.
This requirement allows the API to be compatible across Python 2 and
Python 3.New features:Support for Python 3.1.2.0 (2016-09-20)New features:kt.testing.requests.RequestInfoobject encapsulates information
received byrequestsfrom the application.  This replaces a
5-tuple stored in therequestsattribute of the fixture componentkt.testing.requests.Requests, and provides named access to parts
of the provided data, for better readability in tests.1.1.0 (2016-05-10)New features:kt.testing.requests.Requestsmethodsadd_errorandadd_responsegrew a new, optional parameter,filter, which
accepts a callable with the same signature asrequests.request.
The result is a Boolean value that indicates whether request should be
considered a match for the response.  The filter function will only be
called if the method and URL match.This can be used to check whether request body matches some
expectation.  This can be especially valuable for RPC-type interfaces
(XML-RPC or SOAP, for example) where several behaviors map to the same
URL and HTTP method.Newkt.testing.requests.Requestsmethods:add_connect_timeout,add_read_timeout,add_unreachable_host, to add the
corresponding exceptions to the set of configured responses.1.0.0 (2016-03-21)Initial public release of library initialy created for internal use atKeeper Technology.Implementing fixture componentsFixture components are defined by a factory object, usually a class, and
are expected to provide a slim API for the harness.  Let’s look at a
simple but complete, usable example:import logging


class TestLoggingHandler(logging.StreamHandler):

    def __init__(self, stream, records):
        self.records = records
        super(TestLoggingHandler, self).__init__(stream)

    def handle(self, record):
        self.records.append(record)
        super(TestLoggingHandler, self).handle(record)


class LoggingFixture(object):

    def __init__(self, test, name=None):
        self.test = test
        self.name = name

    def setup(self):
        sio = cStringIO.StringIO()
        self.output = sio.getvalue
        self.records = []
        handler = TestLoggingHandler(sio, self.records)
        logger = logging.getLogger(self.name)
        logger.addHandler(handler)
        self.test.addCleanup(logger.removeHandler, handler)Using this from a test fixture is straightforward:import kt.testing


class TestMyThing(kt.testing.TestCase):

    logging = kt.testing.compose(LoggingFixture)

    def test_some_logging(self):
        logging.getLogger('my.package').error('not happy')

        record = self.logging.records[-1]

        self.assertEqual(record.getMessage(), 'not happy')
        self.assertEqual(record.levelname, 'ERROR')Fixture components may also provide ateardownmethod that takes no
arguments (aside from self).  These are called after thetearDownmethod of the test case is invoked, and do not require that method to be
successful.  (They are invoked as cleanup functions of the test case.)Constructor arguments for the fixture component can be provided withkt.testing.compose, but note that the test case instance will always
be passed as the first positional argument:class TestMyThing(kt.testing.TestCase):

    logging = kt.testing.compose(LoggingFixture, name='my.package')

    def test_some_logging(self):
        logging.getLogger('your.package').error('not happy')

        with self.assertRaises(IndexError):
            self.logging.records[-1]Each instance of the test case class will get it’s own instance of the
fixture components, accessible via the properties defined usingkt.testing.compose.  These instances will already be available when
the__init__method of the test case is invoked.If the test class overrides thesetUpmethod, it will need to ensure
the superclasssetUpis invoked so thesetupmethod of the
fixture components are invoked:class TestSomeThing(kt.testing.TestCase):

    logging = kt.testing.compose(LoggingFixture, name='my.package')

    def setUp(self):
        super(TestSomeThing, self).setUp()
        # more stuff hereNote that thesetUpdidn’t invokeunittest.TestCase.setUpdirectly.  Sincekt.testing.composecan cause an additional mix-in
class to be added,superis the way to go unless you’re specifically
using a base class that’s known to have the right mix-in already mixed.Multiple fixtures and test inheritanceMultiple fixture components of the same or different types can be added
for a single test class:class TestMyThing(kt.testing.TestCase):

    my = kt.testing.compose(LoggingFixture, name='my.package')
    your = kt.testing.compose(LoggingFixture, name='your.package')

    def test_different(self):
        self.assertIsNot(self.my, self.your)Base classes that use fixture components will be properly initialized,
and properties can be aliased and overridden in ways that make sense:class TestAnotherThing(TestMyThing):

    orig_my = TestMyThing.my
    my = kt.testing.compose(LoggingFixture, name='my.another')

    def test_different(self):
        self.assertIsNot(self.my, self.your)
        self.assertIsNot(self.orig_my, self.your)
        self.assertIsNot(self.orig_my, self.my)

        self.assertEqual(self.my.name, 'my.another')
        self.assertEqual(self.orig_my.name, 'my.package')
        self.assertEqual(self.your.name, 'your.package')kt.testing.requests- Intercession forrequestsMany applications (and other libraries) use therequestspackage to
retrieve resources identified by URL.  It’s often reasonable to usemockdirectly to handle requests for resources in tests, but
sometimes a little more is warranted.  Therequestslibrary provides
multiple ways to trigger particular requests, and applications usually
shouldn’t care which is used to make a request.A fixture component forrequestsis provided:class TestMyApplication(kt.testing.TestCase):

    requests = kt.testing.compose(kt.testing.requests.Requests)A default response entity can be provided via constructor arguments
passed throughcompose.  The body and content-type can both be
provided:class TestMyApplication(kt.testing.TestCase):

    requests = kt.testing.compose(
        kt.testing.requests.Requests,
        body='{"success": true, "value": "let's have some json data"}',
        content_type='application/json',
    )If the default response entity is not defined, an empty body of type
text/plain is used.The fixture provides these methods for configuring responses for
particular requests by URL:add_response(method, url, status=200, body=None,headers={},filter=None)Provide a particular response for a given URL and request method.
Other aspects of the request are not considered for identifying what
response to provide.If the response status indicates an entity is allowed in the
response andbodyis provided asNone, the default body and
content-type will be returned.  This will be an empty string unless
some other value is provided to the fixture component constructor.
If the status indicates no entity should be returned, an empty body
will be used.Iffilteris provided and notNone, if must be a callable that
accepts the same signature asrequests.requestand returns a
Boolean value indicating whether than response applies to the
request being made.  If the result is true, the response is
considered a match and will be consumed.  If false, the response
will not be used, but will be considered for subsequent requests.The provided information will be used to create a response that is
returned by therequestsAPI.add_error(method, url, exception, filter=None)Provide an exception that should be raised when a particular
resource is requested.  This can be used to simulate errors such as
a non-responsive server or DNS resolution failure.  Only the URL and
request method are considered for identifying what response to
provide.add_connect_timeout(method, url, filter=None)Provide an exception structured the same way as it would be were the
host not to connect within a reasonable time.  This usesadd_error, but saves having to construct the exception yourself.add_read_timeout(method, url, filter=None)Provide an exception structured the same way as it would be were the
host to connect but not respond within a reasonable time.  This usesadd_error, but saves having to construct the exception yourself.add_unreachable_host(method, url, filter=None)Provide an exception structured the same way as it would be were the
host unreachable.  This usesadd_error, but saves having to
construct the exception yourself.If a request is made that does match any provided response, anAssertionErroris raised; this will normally cause a test to fail,
unless the code under test catches exceptions too aggressively.A test that completes without consuming all configured responses will
cause anAssertionErrorto be raised during teardown.  Test runners
based onunittestwill usually report this as an error rather than a
failure, but it’ll require a developer to take a look, and that’s the
point.If multiple configurations are made for the same request method and URL
(whether responses or errors), they’ll be provided to the application in
the order configured.kt.testing.cleanup- Global cleanup registrationMany libraries and applications end up maintaining small bits of global
state.  These bits may be caches, or information derived from
configuration, but they need to be cleared between tests to avoid tests
interfering with each other in ways that can be painful to debug.Clearing these bits of module state in thesetUportearDownmethods of tests takes care of the problem, but each application needs
to be aware of every such bit of module state that exists in the
libraries and application; this can be a challenge.Allowing each library or module to register a cleanup function makes it
possible to collect everything that’s needed to ensure test cleanup can
be sufficient.This approach was built in thezope.testingpackage’scleanupmodule, which provided functions to register and invoke cleanup
functions.  Thekt.testing.cleanupmodule provides a similar API.
Ifzope.testing.cleanupis also used,kt.testing.cleanupcooperates by sharing the behind-the-scenes registry of cleanup
functions.There are two functions which provide thekt.testing.cleanupAPI:register(func, *args, **kwargs)Register a callable that should be invoked to clean up module
state.  The callable will be invoked with the provided additional
positional and keyword arguments.funcshould be fast and simple, and must not raise an
exception.cleanup()Invoke all registered cleanups.  The cleanup functions will be
invoked in the order registered.  Ifzope.testing.cleanupwas
also used, cleanups registered via each API may be intermingled,
according to the order of registration.ThesetUpandtearDownmethods ofkt.testing.TestCaseboth
invoke thecleanupfunction.