Skip to main content

Auxiliary library for writing tests

Project description

Coverage Status Total alerts Language grade: Python

vutils-testing: Auxiliary Library for Writing Tests

This package provides a set of tools that help with writing tests. It helps with creating test data and types, mocking objects, patching, and verifying test results.

Installation

To install the package, type

$ pip install vutils-testing

How to Use

For more details, please follow the subsections below.

Type Factories

Sometimes tests require new types to be defined. To do this, vutils.testing.utils provides make_type function, which is a wrapper of type:

# Create type derived directly from object:
my_type = make_type("MyType")

# Create class derived directly from Exception:
my_error = make_type("MyError", Exception)

# Create class derived from A and B:
my_class = make_type("MyClass", (A, B))

# Create class derived from A with foo member:
my_another_class = make_type("MyOtherClass", A, {"foo": 42})

# Create class derived from object with foo member:
my_test_class = make_type("MyTestClass", members={"foo": 42})

# Key-value arguments other than bases and members are passed to
# __init_subclass__:
my_fourth_class = make_type("MyFourthClass", bases=A, foo=42)

Mocking Objects and Patching

make_mock, make_callable, and PatcherFactory from vutils.testing.mock allow to create mock objects and patching things.

make_mock(*args, **kwargs) is a shortcut for unittest.mock.Mock

make_callable(x) creates also instance of unittest.mock.Mock, but it specifies its function-related behavior: if x is callable, it is used to do a side-effect, otherwise it is used as the return value.

# func_a() returns 3
func_a = make_callable(3)

container = []

# func_b() appends 42 to container
func_b = make_callable(lambda *x, **y: container.append(42))

# func_c() returns func_b
func_c = make_callable(lambda *x, **y: func_b)

PatcherFactory allows to use unittest.mock.patch multiple-times without need of nested with statements. When instantiated, setup method is called. setup method, implemented in the subclass, then may define set of patcher specifications via add_spec method:

class MyPatcher(PatcherFactory):

    @staticmethod
    def setup_foo(mock):
        mock.foo = "foo"

    @staticmethod
    def setup_baz(baz):
        baz["quux"] = 42

    def setup(self):
        self.baz = {}
        # When self.patch() is called:
        # - create a mock object, apply setup_foo on it, and patch foopkg.foo
        #   with it:
        self.add_spec("foopkg.foo", self.setup_foo)
        # - patch foopkg.bar with 42:
        self.add_spec("foopkg.bar", new=42)
        # - apply setup_baz on baz and patch foopkg.baz with it (create=True
        #   and other possible key-value arguments are passed to
        #   unittest.mock.patch):
        self.add_spec("foopkg.baz", self.setup_baz, new=self.baz, create=True)

patcher = MyPatcher()

with patcher.patch():
   # Patches are applied in order as specified by add_spec and reverted in
   # reverse order.
   do_something()

Covering mypy Specific Code

When a module contains code that is visible only to mypy, it is not executed during unit tests and hence reported as not covered. Function cover_typing from vutils.testing.utils module has the ability to execute such a code and therefore improve coverage reports:

# In foopkg/foo.py module:
if typing.TYPE_CHECKING:
    from foopkg import _A, _B, _C

# In test_foo.py:
from foopkg.foo import func_a

# Use after imports so module cache is populated with proper modules. When
# called, following happens:
# - typing.TYPE_CHECKING is patched to True
# - foopkg is patched with _A, _B, and _C symbols if they are not exist
# - finally, foopkg.foo is reloaded
cover_typing("foopkg.foo", ["_A", "_B", "_C"])

Enhanced TestCase

Module vutils.testing.testcase provides TestCase which is a subclass of unittest.TestCase extended about these methods:

  • assert_called_with - assert that the mock object has been called once with the specified arguments and then reset it:
    class ExampleTestCase(TestCase):
        def test_assert_called_with(self):
            mock = make_mock(["foo"])
    
            mock.foo(1, 2, bar=3)
            self.assert_called_with(mock, 1, 2, bar=3)
    
            mock.foo(4)
            self.assert_called_with(mock, 4)
    
  • assert_not_called - assert that the mock object has not been called:
    class ExampleTestCase(TestCase):
        def test_assert_not_called(self):
            mock = make_mock(["foo"])
    
            self.assert_not_called(mock.foo)
    

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vutils-testing-0.3.0.tar.gz (11.2 kB view hashes)

Uploaded Source

Built Distribution

vutils_testing-0.3.0-py2.py3-none-any.whl (10.1 kB view hashes)

Uploaded Python 2 Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page