Helpers for unittest

AnyBlok provides base test classes to help creating fixtures. Blok developers will be mostly interested in BlokTestCase.

Base classes for unit/integration tests with anyblok.

This module provides BlokTestCase, which is the main one meant for blok tests, and DBTestCase, whose primary purpose is to test anyblok itself, in so-called “framework tests”.

TestCase

from anyblok.tests.testcase import TestCase
class anyblok.tests.testcase.TestCase(methodName='runTest')

Bases: unittest.case.TestCase

Common helpers, not meant to be used directly.

Configuration(**values)

Add Configuration value only in the contextmanager

with TestCase.Configuration(db_name='a db name'):
    self.assertEqual(Configuration.get('db_name'), 'a db name')
Parameters:**values – values to update
classmethod additional_setting()
callCleanUp()
cleanUp()
classmethod createdb(keep_existing=False)

Create the database specified in configuration.

cls.init_configuration_manager()
cls.createdb()
Parameters:keep_existing – If false drop the previous db before create it
classmethod dropdb()

Drop the database specified in configuration.

cls.init_configuration_manager()
cls.dropdb()
classmethod getRegistry()

Return the registry for the test database.

This assumes the database is created, and the registry has already been initialized:

registry = self.getRegistry()
Return type:registry instance
classmethod init_configuration_manager(**env)

Initialise the configuration manager with environ variable to launch the test

Warning

For the moment we not use the environ variable juste constante

Parameters:
  • prefix – prefix the database name
  • env – add another dict to merge with environ variable
setUp()
tearDown()

Roll back the session

DBTestCase

Warning

this testcase destroys the test database for each unittest

class anyblok.tests.testcase.DBTestCase(methodName='runTest')

Bases: anyblok.tests.testcase.TestCase

Base class for tests that need to work on an empty database.

Warning

The database is created and dropped with each unit test

For instance, this is the one used for Field, Column, RelationShip, and more generally core framework tests.

The drawback of using this base class is that tests will be slow. The advantage is ultimate test isolation.

Sample usage:

from anyblok.tests.testcase import DBTestCase


def simple_column(ColumnType=None, **kwargs):

    @Declarations.register(Declarations.Model)
    class Test:

        id = Declarations.Column.Integer(primary_key=True)
        col = ColumnType(**kwargs)


class TestColumns(DBTestCase):

    def test_integer(self):
        Integer = Declarations.Column.Integer

        registry = self.init_registry(simple_column,
                                      ColumnType=Integer)
        test = registry.Test.insert(col=1)
        self.assertEqual(test.col, 1)
blok_entry_points = ('bloks',)

setuptools entry points to load blok

init_registry(function, **kwargs)

call a function to filled the blok manager with new model

Parameters:
  • function – function to call
  • kwargs – kwargs for the function
Return type:

registry instance

setUp()

Create a database and load the blok manager

classmethod setUpClass()

Intialialise the configuration manager

tearDown()

Clear the registry, unload the blok manager and drop the database

BlokTestCase

class anyblok.tests.testcase.BlokTestCase(methodName='runTest')

Bases: unittest.case.TestCase

Base class for tests meant to run on a preinstalled database.

The tests written with this class don’t need to start afresh on a new database, and therefore run much faster than those inheriting DBTestCase. Instead, they expect the tested bloks to be already installed and up to date.

The session gets rollbacked after each test.

Such tests are appropriate for a typical blok developper workflow:

  • create and install the bloks once
  • run the tests of the blok under development repeatedly
  • upgrade the bloks in database when needed (schema change, update of dependencies)

They are also appropriate for on the fly testing while installing the bloks: the tests of each blok get run on the database state they expect, before dependent (downstream) bloks, that could. e.g., alter the database schema, get themselves installed. This is useful to test a whole stack at once using only one database (typically in CI bots).

Sample usage:

from anyblok.tests.testcase import BlokTestCase


class MyBlokTest(BlokTestCase):

    def test_1(self):
        # access to the registry by ``self.registry``
        ...
classmethod additional_setting()
callCleanUp()
cleanUp()
registry = None

The instance of anyblok.registry.Registry` to use in tests.

The session_commit() method is disabled to avoid side effects from one test to the other.

setUp()
classmethod setUpClass()

Initialize the registry.

tearDown()

Roll back the session

LogCapture

class anyblok.tests.testcase.LogCapture(names=None, install=True, level=1, propagate=None, attributes=('name', 'levelname', 'getMessage'), recursive_check=False)

Bases: testfixtures.logcapture.LogCapture

Overwrite testfixtures.LogCapture to add some helper methods

acquire()

Acquire the I/O thread lock.

actual()
addFilter(filter)

Add the specified filter to this handler.

atexit()
atexit_setup = False
check(*expected)

This will compare the captured entries with the expected entries provided and raise an AssertionError if they do not match.

Parameters:expected – A sequence of 3-tuples containing the expected log entries. Each tuple should be of the form (logger_name, string_level, message)
clear()

Clear any entries that have been captured.

close()

Tidy up any resources used by the handler.

This version removes the handler from an internal map of handlers, _handlers, which is used for handler lookup by name. Subclasses should ensure that this gets called from overridden close() methods.

createLock()

Acquire a thread lock for serializing access to the underlying I/O.

emit(record)
filter(record)

Determine if a record is loggable by consulting all the filters.

The default is to allow the record to be logged; any filter can veto this and the record is then dropped. Returns a zero value if a record is to be dropped, else non-zero.

Changed in version 3.2: Allow filters to be just callables.

flush()

Ensure all logging output has been flushed.

This version does nothing and is intended to be implemented by subclasses.

format(record)

Format the specified record.

If a formatter is set, use it. Otherwise, use the default formatter for the module.

get_critical_messages()

Return only the logging.CRITICAL messages

get_debug_messages()

Return only the logging.DEBUG messages

get_error_messages()

Return only the logging.ERROR messages

get_info_messages()

Return only the logging.INFO messages

get_messages(*levels)

Return the captured messages

with LogCapture() as logs:
    messages = logs.get_messages(INFO, WARNING)
Parameters:*levels – list of logging.level
Return type:list of formated message
get_name()
get_warning_messages()

Return only the logging.WARNING messages

handle(record)

Conditionally emit the specified logging record.

Emission depends on filters which may have been added to the handler. Wrap the actual emission of the record with acquisition/release of the I/O thread lock. Returns whether the filter passed the record for emission.

handleError(record)

Handle errors which occur during an emit() call.

This method should be called from handlers when an exception is encountered during an emit() call. If raiseExceptions is false, exceptions get silently ignored. This is what is mostly wanted for a logging system - most users will not care about errors in the logging system, they are more interested in application errors. You could, however, replace this with a custom handler if you wish. The record which was being processed is passed in to this method.

install()

Install this LogHandler into the Python logging framework for the named loggers.

This will remove any existing handlers for those loggers and drop their level to that specified on this LogCapture in order to capture all logging.

installed = False
instances = set()
name
release()

Release the I/O thread lock.

removeFilter(filter)

Remove the specified filter from this handler.

setFormatter(fmt)

Set the formatter for this handler.

setLevel(level)

Set the logging level of this handler. level must be an int or a str.

set_name(name)
uninstall()

Un-install this LogHandler from the Python logging framework for the named loggers.

This will re-instate any existing handlers for those loggers that were removed during installation and retore their level that prior to installation.

uninstall_all()

This will uninstall all existing LogHandler objects.