Skip to main content

Coverage Status CodeQL

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("MyAnotherClass", 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()

Deferred Instance Initialization

Patching may take no effect if the patched object appears in constructor and this constructor is called outside of patcher context. LazyInstance from vutils.testing.utils can defer initialization up to the time of method call:

class StderrWriter:
    def __init__(self):
        self.stream = sys.stderr

    def write(self, text):
        self.stream.write(text)

class StderrPatcher(PatcherFactory):
    def setup(self):
        self.stream = io.StringIO
        self.add_spec("sys.stderr", new=self.stream)

class MyTestCase(TestCase):
    def test_deferred_initialization(self):
        writerA = StderrWriter()
        writerB = LazyInstance(StderrWriter).create()
        patcher = StderrPatcher()

        # Patch sys.stderr:
        with patcher.patch():
            # Write Hello! to standard error output:
            writerA.write("Hello!\n")
            # Write Hi! to StringIO instance:
            writerB.write("Hi!\n")

Deferred assertRaises

Sometimes there are callable objects with a very similar prototypes and behavior so they can be run and checked with one universal function. However, if one of them raises an exception under specific circumstances, this must be also handled by the universal function, which adds to its complexity. For this reason, vutils.testing.utils introduces AssertRaises class which wraps exception raising assertions:

class FooError(Exception):
    detail = "foo"

def func_a(obj):
    obj.foo = 42

def func_b(obj):
    func_a(obj)
    raise FooError()

def Foo(TestCase):
    def run_and_check(self, func):
        obj = make_mock()
        func(obj)
        self.assertEqual(obj.foo, 42)

    def test_func(self):
        wfunc_b = AssertRaises(self, func_b, FooError)

        self.run_and_check(func_a)
        # Catch and store FooError:
        self.run_and_check(wfunc_b)
        # Check the caught exception:
        self.assertEqual(wfunc_b.get_exception().detail, "foo")

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)
    

Metadata

Release files for vutils-testing 2.0.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for vutils-testing 2.0.3
File Size Uploaded Provenance Actions
vutils_testing-2.0.3.tar.gz 18.0 kB Without provenance Details for vutils_testing-2.0.3.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for vutils-testing 2.0.3
File Interpreter ABI Platform Actions
vutils_testing-2.0.3-py3-none-any.whl Python 3 none any Details for vutils_testing-2.0.3-py3-none-any.whl

Total release size: 30.5 kB

Release files / vutils_testing-2.0.3.tar.gz

Download URL vutils_testing-2.0.3.tar.gz
Size 18.0 kB
Tags Source
SHA-256 checksum
How to use checksums
83ed12fe0857ad7d82bac995cb5312ce7cc1bb7d136c6ce0dc526e67161ace96
BLAKE2b-256 checksum
How to use checksums
56dfc028d6a7f1cf36b8b2b3ed27471864981be470ababdec54c5ea25e9d8b36
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/5.1.1 CPython/3.12.7

Release files / vutils_testing-2.0.3-py3-none-any.whl

Download URL vutils_testing-2.0.3-py3-none-any.whl
Size 12.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b93f1555503329756db205a88fbf92b5ec84eb885b721e4bda9379e31fcebb05
BLAKE2b-256 checksum
How to use checksums
9b7568ab8df22b65759b5a9e44e202d6ac4790c085809bdcd580e35cfb6a53dc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/5.1.1 CPython/3.12.7

Security for vutils-testing 2.0.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page