repeated-test


Namerepeated-test JSON
Version 2.3.3 PyPI version JSON
download
home_pagehttps://github.com/epsy/repeated_test
SummaryA quick unittest-compatible framework for repeating a test function over many fixtures
upload_time2023-07-18 07:02:05
maintainer
docs_urlNone
authorYann Kaiser
requires_python>=3.5
licenseMIT
keywords test testing unittest fixtures
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI
coveralls test coverage
            .. |ut| replace:: unittest
.. _ut: http://docs.python.org/3/library/unittest.html

.. |tc| replace:: unittest.TestCase
.. _tc: http://docs.python.org/3/library/unittest.html#unittest.TestCase

.. |subtests| replace:: subtests
.. _subtests: https://docs.python.org/3/library/unittest.html#subtests

.. |pyt| replace:: pytest
.. _pyt: https://docs.pytest.org/en/stable/contents.html

.. |pytest-subtests| replace:: pytest-subtests
.. _pytest-subtests: https://pypi.org/project/pytest-subtests/

.. _repeated_test:

*************
repeated_test
*************

.. image:: https://badges.gitter.im/epsy/repeated_test.svg
   :alt: Join the chat at https://gitter.im/epsy/repeated_test
   :target: https://gitter.im/epsy/repeated_test?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
.. image:: https://github.com/epsy/repeated_test/actions/workflows/ci.yml/badge.svg?branch=master
    :target: https://github.com/epsy/repeated_test/actions/workflows/ci.yml
.. image:: https://coveralls.io/repos/github/epsy/repeated_test/badge.svg?branch=master
    :target: https://coveralls.io/github/epsy/repeated_test?branch=master

``repeated_test`` lets you write tests that apply the same function to
many sets of parameters.


.. _example:

For instance:

.. code-block:: python

    from repeated_test import Fixtures

    class MyFixtures(Fixtures):
        def _test(self, expected, *terms):
            self.assertEqual(expected, sum(terms))

        a = 10, 5, 5
        b = 15, 7, 8
        c = 42, 1, 1

The result is unittest-compatible, and provides useful context in the
traceback in case of errors:

.. code-block:: console

    $ python -m unittest my_tests
    ..F
    ======================================================================
    FAIL: test_c (my_tests.MyFixtures)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "my_tests.py", line 9, in MyFixtures
        c = 42, 1, 1
      File "my_tests.py", line 5, in _test
        self.assertEqual(expected, sum(terms))
    AssertionError: 42 != 2

    ----------------------------------------------------------------------
    Ran 3 tests in 0.002s

    FAILED (failures=1)

.. _install:

You can install it using:

.. code-block:: console

    $ pip install --user repeated_test


.. _help:

Help / Issues
=============

You can get help in the
`gitter.im chatroom <https://gitter.im/epsy/repeated_test>`_.

If you find any issues or have any requests, use
`GitHub Issues <https://github.com/epsy/repeated_test/issues>`_.


.. _reference:

Reference
=========

.. _intro:

Introduction
------------

Python's |ut|_ modules helps in performing various forms of automated testing.
One writes a class deriving from |tc|_ and adds various ``test_xyz`` methods.
Test runners run these tests, keeping count of successful and failed tests,
and produces a trace with the causes of these failures.

Sometimes it makes sense to have one test be carried out for a large amount
of different inputs.
This module aims to provide an efficient way to do this.

It allows you to write fixtures (inputs) as plain members of a
class, and bind a test function to them. This test function is called for each
fixture as you will see below. The produced class is a |tc|_ subclass, so it is
compatible with |ut|_ and other |ut|-compatible test runners.


.. _testcase:

Building a test case
--------------------

In order to produce a |tc|_, ``repeated_test`` requires you to:

* Subclass ``repeated_test.Fixtures``
* Write a ``_test`` method that takes a few parameters, making use of any
  |tc|_ method it needs
* Assign fixtures directly in the class body, which are then unpacked as
  arguments to the ``_test`` method (as in ``_test(*args)``)

You can use any |tc|_ methods in your test function, such as ``assertEqual()``
and so forth.

.. code-block:: python

    from repeated_test import Fixtures

    class MyFixtures(Fixtures):
        def _test(self, arg1, arg2, arg3):
            self.assertEqual(..., ...)

        Ps = 'p1', 'p2', 'p3'
        # _test(*Ps) will be called, ie. _test('p1', p2', 'p3')

        Qs = 'q1', 'q2', 'q3'
        # _test(*Qs) will be called, ie. _test('q1', q2', 'q3')

Make sure that your fixture tuples provide the correct amount of arguments
for your ``_test`` method, unless it has an ``*args`` parameter.


.. _running:

Running a test case
-------------------

You can run a ``repeated_test`` test case like any other |tc|_ class:

.. code-block:: shell

    python -m unittest
    python -m unittest my_test_module
    python -m unittest my_test_module.MyFixtures

    # To refer to an individual test, prefix the name of the fixture with "test_"
    python -m unittest my_test_module.MyFixtures.test_Ps

Learn more in the `official unittest docs <https://docs.python.org/3/library/unittest.html#command-line-interface>`_.

You can also use a |ut|-compatible test runer, like |pyt|_:

.. code-block:: shell

    python -m pytest
    python -m pytest my_test_module.py
    python -m pytest my_test_module.py -k MyFixtures
    python -m pytest my_test_module.py -k test_Ps
    python -m pytest my_test_module.py::MyFixtures::test_Ps

Learn more in the `official pytest docs <https://docs.pytest.org/en/stable/how-to/usage.html>`_

.. _options:

Passing in keyword arguments
----------------------------

You can pass in keyword arguments using ``repeated_test.options``:

.. code-block:: python

    import sys

    from repeated_test import Fixtures, options

    class MyFixtures(Fixtures):
        def _test(self, arg1, arg2, *, min_version=None, max_version=None):
            ...

        not_using_versions = "abc", "abc"
        # -> _test("abc", "abc")

        using_max_version = "abc", "abc", options(max_version=(3, 9))
        # -> _test("abc", "abc", max_version=(3, 9))

        using_both_versions = "abc", "abc", options(min_version=(3, 8), max_version=(3, 9))
        # -> _test("abc", "abc", min_version=(3, 8), max_version=(3, 9))

        using_both_versions_2 = "abc", "abc", options(min_version=(3, 8)), options(max_version=(3, 9))
        # Same, but by specifying options separately

This can be useful if you have multiple options that are only used some of the time.

.. _manage-options:

Passing in keyword arguments to multiple tests
----------------------------------------------

If you are re-using the same keyword arguments across multiple tests,
there are several ways to do so:

- Using ``@repeated_test.with_options(...)`` lets you
  specify options for every fixture within a class.
- Using ``with repeated_test.options(...)`` lets you
  specify options for every fixture within the ``with`` block.
- You can continue using ``options()`` on individual fixtures,
  and override values provided by surrounding code.
- You can use ``repeated_test.skip_option`` to stop supplying any argument.
  The argument won't be supplied to the function,
  which is useful for using a default value,
  or for removing common options from a class whose test function doesn't handle

.. code-block:: python

    from repeated_test import Fixtures, options, with_options

    @with_options(kwarg1="value from decorator")
    class MyFixtures(Fixtures):
        def _test(self, arg1, arg2, *, kwarg1, kwarg2="default"):
            ...

        using_provided_values = "arg1", "arg2"
        # -> _test("arg1", "arg2", kwarg1="value from decorator", kwarg2="default")

        overriding_provided_values = "arg1", "arg2", options(kwarg1="kwarg1", kwarg2="kwarg2")
        # -> _test("arg1", "arg2", kwarg1="kwarg1", kwarg2="kwarg2")

        with options(kwarg1="value from context manager"):
            using_value_from_context_manager = "arg1", "arg2"
            # -> _test("arg1", "arg2", kwarg1="value from context manager", kwarg2="default")

            overriding_value_from_context_manager = "arg1", "arg2", options(kwarg1="kwarg1")
            # -> _test("arg1", "arg2", kwarg1="kwarg1", kwarg2="default")

        with options(kwarg2="value from context manager"):
            removing_value = "arg1", "arg2"
            # -> _test("arg1", "arg2", kwarg1="value from decorator", kwarg2="value from context manager")
            removing_value = "arg1", "arg2", options(kwarg2=skip_option)
            # -> _test("arg1", "arg2", kwarg1="value from decorator", kwarg2="default")

.. _options-matrix:

Testing multiple values for a keyword parameter
-----------------------------------------------

You can also use ``@with_options_matrix``
to provide multiple values for a keyword parameter.
``repeated_test`` will run every combination
except for parameters that are overridden.

.. code-block:: python

    from repeated_test import Fixtures, options, with_options_matrix


    @with_options_matrix(
        spam=["spam1", "spam2"],
        ham=["ham1", "ham2"],
    )
    class MyFixtures(Fixtures):
        def _test(self, arg1, arg2, *, spam, ham):
            ...

        using_provided_values = "arg1", "arg2"
        # -> _test("arg1", "arg2", spam="spam1", ham="ham1")
        # -> _test("arg1", "arg2", spam="spam1", ham="ham2")
        # -> _test("arg1", "arg2", spam="spam2", ham="ham1")
        # -> _test("arg1", "arg2", spam="spam2", ham="ham2")

        with options(spam="spam"):
            overriding_one_value = "arg1", "arg2"
            # -> _test("arg1", "arg2", spam="spam", ham="ham1")
            # -> _test("arg1", "arg2", spam="spam", ham="ham2")

``repeated_test`` will report each combination using unittest's |subtests|_ feature.
|pyt| does not have this feature built-in, but the |pytest-subtests|_ plugin adds support.

.. code-block:: console

    ======================================================================
    FAIL: test_overriding_one_value (example_options._test) (ham='ham1')
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "/home/myself/repeated_test/example_options.py", line 41, in MyFixtures
        overriding_one_value = "arg1", "arg2"
      File "/home/myself/repeated_test/example_options.py", line 32, in _test
        self.fail("example failure")
    AssertionError: example failure

    ======================================================================
    FAIL: test_overriding_one_value (example_options._test) (ham='ham2')
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "/home/myself/repeated_test/example_options.py", line 41, in MyFixtures
        overriding_one_value = "arg1", "arg2"
      File "/home/myself/repeated_test/example_options.py", line 32, in _test
        self.fail("example failure")
    AssertionError: example failure

.. _evaluated:

Evaluated test case input
-------------------------

You can use ``@evaluated`` to make
a function that can be inserted in a test case tuple.
When running the test,
the function will be called,
and the result will be spliced into the test case tuple:

.. code-block:: python

    from repeated_test import Fixtures, evaluated

    class EvaluatedFixtures(Fixtures):
        def _test(self, a, b, c):
            pass

        @evaluated
        def fully_evaluated(self):
            return (1 + 1, 2, 3)
        # -> _test(2, 2, 3)

        @evaluated
        def _helper():
            return (1 + 2, 3)
        partly_evaluated = _helper(), 4
        # -> _test(3, 3, 4)

The wrapped function must always return a tuple.

The wrapped function will also receive options as keyword arguments:

.. code-block:: python

    from repeated_test import Fixtures, evaluated, with_options_matrix

    @with_options_matrix(
        option=[
            "option 1",
            "option 2",
        ],
    )
    class EvaluatedFixturesWithOptions(Fixtures):
        def _test(self, a, *, option):
            pass

        @evaluated
        def _helper(arg, *, option):
            return (f"{arg}-{option}",)

        using_option_in_evaluated = _helper("arg")
        # -> _test("arg-option 1", option="option 1")
        # -> _test("arg-option 2", option="option 2")

.. _named alternative:

Named alternatives
------------------

When using ``with_options_matrix``,
sometimes the repr generated by those options is difficult to read.
This can be the case with functions,
which can end up showing as something like
``<function myfunc at 0x7f9f5e506280>``.

You can use ``NamedAlternative`` to give them a name:

.. code-block:: python

    from repeated_test import NamedAlternative

    value1 = NamedAlternative("name for value1", "value1")

    @NamedAlternative("name for func1")
    def func1():
        pass

.. _naming:
.. _escaping:

Naming and escaping
-------------------

You may name your test tuples however you like, though they may not start with
``test_`` or ``_``. They are copied to the resulting |tc|_ class, and test
methods are created for them. Their name is that of the tuple, prefixed with
``test_``.

.. _regular test methods:
.. _regular:

Members starting with ``test_`` or ``_`` are directly copied over to the
resulting |tc|_ class, without being treated as fixtures. You can use this to
insert regular tests amongst your fixtures, or constants that you do not wish
to be treated as tests:

.. code-block:: python

    from repeated_test import Fixtures

    class MyFixtures(Fixtures):
        def _test(self, arg1, arg2, arg3):
            self.assertEqual(..., ...)

        def test_other(self):
            self.assertEqual(3, 1+2)

        _spam = 'spam, bacon and eggs'
        # _spam won't be treated as a fixture, so _test(*_spam) won't be called

        ham = _spam, _spam, _spam

You may even call the test function using ``self._test(...)`` if necessary.


.. _separate:

Separating tests and fixtures
-----------------------------

You can apply a fixtures class to a different test function using its
``with_test`` method:

.. code-block:: python

    class MyFixtures(Fixtures):
        _test = None
        ...

    @MyFixtures.with_test
    def other_test(self, arg1, arg2, arg3):
        self.assertEqual(..., ...)

While the function appears out of any class, it will be used as a method of
the resulting |tc|_ class, so keep in mind that it takes a ``self`` parameter.

You can reuse a fixture class however many times you like.

If you specify a test function this way, you can set ``_test = None``
in your fixtures definition. However, it will not be discovered by |ut|_,
so `regular test methods`_ won't be run.
Omitting ``_test`` completely raises an error in order to prevent accidentally
disabling your tests.


.. _decorator:

Working with functions as fixtures
----------------------------------

It can be fairly impractical to use functions in your fixture tuples in this
scheme. If your fixture tuple is meant to have one function in it, you can
use the ``tup`` decorator:

.. code-block:: python

    from repeated_test import Fixtures, tup

    class my_tests(Fixtures):
        def _test(self, func, arg1, arg2):
            self.assertEqual(..., ...)

        @tup('arg1', 'arg2')
        def ham():
            pass
        # equivalent to
        def _ham():
            pass
        ham = _ham, 'arg1', 'arg2'


.. _non-unittest:

Replacing |tc| with another class
---------------------------------

You can replace |tc| with another class using ``WithTestClass(cls)``.

For instance, if you wish to use ``unittest2``:

.. code-block:: python

    import unittest2
    from repeated_test import WithTestClass

    class my_tests(WithTestClass(unittest2.TestCase)):
        ...

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/epsy/repeated_test",
    "name": "repeated-test",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.5",
    "maintainer_email": "",
    "keywords": "test,testing,unittest,fixtures",
    "author": "Yann Kaiser",
    "author_email": "kaiser.yann@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/99/78/0911cdbd699c72701ba6755e7696d075bad52047ad6cd1e8976b08ded099/repeated_test-2.3.3.tar.gz",
    "platform": null,
    "description": ".. |ut| replace:: unittest\n.. _ut: http://docs.python.org/3/library/unittest.html\n\n.. |tc| replace:: unittest.TestCase\n.. _tc: http://docs.python.org/3/library/unittest.html#unittest.TestCase\n\n.. |subtests| replace:: subtests\n.. _subtests: https://docs.python.org/3/library/unittest.html#subtests\n\n.. |pyt| replace:: pytest\n.. _pyt: https://docs.pytest.org/en/stable/contents.html\n\n.. |pytest-subtests| replace:: pytest-subtests\n.. _pytest-subtests: https://pypi.org/project/pytest-subtests/\n\n.. _repeated_test:\n\n*************\nrepeated_test\n*************\n\n.. image:: https://badges.gitter.im/epsy/repeated_test.svg\n   :alt: Join the chat at https://gitter.im/epsy/repeated_test\n   :target: https://gitter.im/epsy/repeated_test?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge\n.. image:: https://github.com/epsy/repeated_test/actions/workflows/ci.yml/badge.svg?branch=master\n    :target: https://github.com/epsy/repeated_test/actions/workflows/ci.yml\n.. image:: https://coveralls.io/repos/github/epsy/repeated_test/badge.svg?branch=master\n    :target: https://coveralls.io/github/epsy/repeated_test?branch=master\n\n``repeated_test`` lets you write tests that apply the same function to\nmany sets of parameters.\n\n\n.. _example:\n\nFor instance:\n\n.. code-block:: python\n\n    from repeated_test import Fixtures\n\n    class MyFixtures(Fixtures):\n        def _test(self, expected, *terms):\n            self.assertEqual(expected, sum(terms))\n\n        a = 10, 5, 5\n        b = 15, 7, 8\n        c = 42, 1, 1\n\nThe result is unittest-compatible, and provides useful context in the\ntraceback in case of errors:\n\n.. code-block:: console\n\n    $ python -m unittest my_tests\n    ..F\n    ======================================================================\n    FAIL: test_c (my_tests.MyFixtures)\n    ----------------------------------------------------------------------\n    Traceback (most recent call last):\n      File \"my_tests.py\", line 9, in MyFixtures\n        c = 42, 1, 1\n      File \"my_tests.py\", line 5, in _test\n        self.assertEqual(expected, sum(terms))\n    AssertionError: 42 != 2\n\n    ----------------------------------------------------------------------\n    Ran 3 tests in 0.002s\n\n    FAILED (failures=1)\n\n.. _install:\n\nYou can install it using:\n\n.. code-block:: console\n\n    $ pip install --user repeated_test\n\n\n.. _help:\n\nHelp / Issues\n=============\n\nYou can get help in the\n`gitter.im chatroom <https://gitter.im/epsy/repeated_test>`_.\n\nIf you find any issues or have any requests, use\n`GitHub Issues <https://github.com/epsy/repeated_test/issues>`_.\n\n\n.. _reference:\n\nReference\n=========\n\n.. _intro:\n\nIntroduction\n------------\n\nPython's |ut|_ modules helps in performing various forms of automated testing.\nOne writes a class deriving from |tc|_ and adds various ``test_xyz`` methods.\nTest runners run these tests, keeping count of successful and failed tests,\nand produces a trace with the causes of these failures.\n\nSometimes it makes sense to have one test be carried out for a large amount\nof different inputs.\nThis module aims to provide an efficient way to do this.\n\nIt allows you to write fixtures (inputs) as plain members of a\nclass, and bind a test function to them. This test function is called for each\nfixture as you will see below. The produced class is a |tc|_ subclass, so it is\ncompatible with |ut|_ and other |ut|-compatible test runners.\n\n\n.. _testcase:\n\nBuilding a test case\n--------------------\n\nIn order to produce a |tc|_, ``repeated_test`` requires you to:\n\n* Subclass ``repeated_test.Fixtures``\n* Write a ``_test`` method that takes a few parameters, making use of any\n  |tc|_ method it needs\n* Assign fixtures directly in the class body, which are then unpacked as\n  arguments to the ``_test`` method (as in ``_test(*args)``)\n\nYou can use any |tc|_ methods in your test function, such as ``assertEqual()``\nand so forth.\n\n.. code-block:: python\n\n    from repeated_test import Fixtures\n\n    class MyFixtures(Fixtures):\n        def _test(self, arg1, arg2, arg3):\n            self.assertEqual(..., ...)\n\n        Ps = 'p1', 'p2', 'p3'\n        # _test(*Ps) will be called, ie. _test('p1', p2', 'p3')\n\n        Qs = 'q1', 'q2', 'q3'\n        # _test(*Qs) will be called, ie. _test('q1', q2', 'q3')\n\nMake sure that your fixture tuples provide the correct amount of arguments\nfor your ``_test`` method, unless it has an ``*args`` parameter.\n\n\n.. _running:\n\nRunning a test case\n-------------------\n\nYou can run a ``repeated_test`` test case like any other |tc|_ class:\n\n.. code-block:: shell\n\n    python -m unittest\n    python -m unittest my_test_module\n    python -m unittest my_test_module.MyFixtures\n\n    # To refer to an individual test, prefix the name of the fixture with \"test_\"\n    python -m unittest my_test_module.MyFixtures.test_Ps\n\nLearn more in the `official unittest docs <https://docs.python.org/3/library/unittest.html#command-line-interface>`_.\n\nYou can also use a |ut|-compatible test runer, like |pyt|_:\n\n.. code-block:: shell\n\n    python -m pytest\n    python -m pytest my_test_module.py\n    python -m pytest my_test_module.py -k MyFixtures\n    python -m pytest my_test_module.py -k test_Ps\n    python -m pytest my_test_module.py::MyFixtures::test_Ps\n\nLearn more in the `official pytest docs <https://docs.pytest.org/en/stable/how-to/usage.html>`_\n\n.. _options:\n\nPassing in keyword arguments\n----------------------------\n\nYou can pass in keyword arguments using ``repeated_test.options``:\n\n.. code-block:: python\n\n    import sys\n\n    from repeated_test import Fixtures, options\n\n    class MyFixtures(Fixtures):\n        def _test(self, arg1, arg2, *, min_version=None, max_version=None):\n            ...\n\n        not_using_versions = \"abc\", \"abc\"\n        # -> _test(\"abc\", \"abc\")\n\n        using_max_version = \"abc\", \"abc\", options(max_version=(3, 9))\n        # -> _test(\"abc\", \"abc\", max_version=(3, 9))\n\n        using_both_versions = \"abc\", \"abc\", options(min_version=(3, 8), max_version=(3, 9))\n        # -> _test(\"abc\", \"abc\", min_version=(3, 8), max_version=(3, 9))\n\n        using_both_versions_2 = \"abc\", \"abc\", options(min_version=(3, 8)), options(max_version=(3, 9))\n        # Same, but by specifying options separately\n\nThis can be useful if you have multiple options that are only used some of the time.\n\n.. _manage-options:\n\nPassing in keyword arguments to multiple tests\n----------------------------------------------\n\nIf you are re-using the same keyword arguments across multiple tests,\nthere are several ways to do so:\n\n- Using ``@repeated_test.with_options(...)`` lets you\n  specify options for every fixture within a class.\n- Using ``with repeated_test.options(...)`` lets you\n  specify options for every fixture within the ``with`` block.\n- You can continue using ``options()`` on individual fixtures,\n  and override values provided by surrounding code.\n- You can use ``repeated_test.skip_option`` to stop supplying any argument.\n  The argument won't be supplied to the function,\n  which is useful for using a default value,\n  or for removing common options from a class whose test function doesn't handle\n\n.. code-block:: python\n\n    from repeated_test import Fixtures, options, with_options\n\n    @with_options(kwarg1=\"value from decorator\")\n    class MyFixtures(Fixtures):\n        def _test(self, arg1, arg2, *, kwarg1, kwarg2=\"default\"):\n            ...\n\n        using_provided_values = \"arg1\", \"arg2\"\n        # -> _test(\"arg1\", \"arg2\", kwarg1=\"value from decorator\", kwarg2=\"default\")\n\n        overriding_provided_values = \"arg1\", \"arg2\", options(kwarg1=\"kwarg1\", kwarg2=\"kwarg2\")\n        # -> _test(\"arg1\", \"arg2\", kwarg1=\"kwarg1\", kwarg2=\"kwarg2\")\n\n        with options(kwarg1=\"value from context manager\"):\n            using_value_from_context_manager = \"arg1\", \"arg2\"\n            # -> _test(\"arg1\", \"arg2\", kwarg1=\"value from context manager\", kwarg2=\"default\")\n\n            overriding_value_from_context_manager = \"arg1\", \"arg2\", options(kwarg1=\"kwarg1\")\n            # -> _test(\"arg1\", \"arg2\", kwarg1=\"kwarg1\", kwarg2=\"default\")\n\n        with options(kwarg2=\"value from context manager\"):\n            removing_value = \"arg1\", \"arg2\"\n            # -> _test(\"arg1\", \"arg2\", kwarg1=\"value from decorator\", kwarg2=\"value from context manager\")\n            removing_value = \"arg1\", \"arg2\", options(kwarg2=skip_option)\n            # -> _test(\"arg1\", \"arg2\", kwarg1=\"value from decorator\", kwarg2=\"default\")\n\n.. _options-matrix:\n\nTesting multiple values for a keyword parameter\n-----------------------------------------------\n\nYou can also use ``@with_options_matrix``\nto provide multiple values for a keyword parameter.\n``repeated_test`` will run every combination\nexcept for parameters that are overridden.\n\n.. code-block:: python\n\n    from repeated_test import Fixtures, options, with_options_matrix\n\n\n    @with_options_matrix(\n        spam=[\"spam1\", \"spam2\"],\n        ham=[\"ham1\", \"ham2\"],\n    )\n    class MyFixtures(Fixtures):\n        def _test(self, arg1, arg2, *, spam, ham):\n            ...\n\n        using_provided_values = \"arg1\", \"arg2\"\n        # -> _test(\"arg1\", \"arg2\", spam=\"spam1\", ham=\"ham1\")\n        # -> _test(\"arg1\", \"arg2\", spam=\"spam1\", ham=\"ham2\")\n        # -> _test(\"arg1\", \"arg2\", spam=\"spam2\", ham=\"ham1\")\n        # -> _test(\"arg1\", \"arg2\", spam=\"spam2\", ham=\"ham2\")\n\n        with options(spam=\"spam\"):\n            overriding_one_value = \"arg1\", \"arg2\"\n            # -> _test(\"arg1\", \"arg2\", spam=\"spam\", ham=\"ham1\")\n            # -> _test(\"arg1\", \"arg2\", spam=\"spam\", ham=\"ham2\")\n\n``repeated_test`` will report each combination using unittest's |subtests|_ feature.\n|pyt| does not have this feature built-in, but the |pytest-subtests|_ plugin adds support.\n\n.. code-block:: console\n\n    ======================================================================\n    FAIL: test_overriding_one_value (example_options._test) (ham='ham1')\n    ----------------------------------------------------------------------\n    Traceback (most recent call last):\n      File \"/home/myself/repeated_test/example_options.py\", line 41, in MyFixtures\n        overriding_one_value = \"arg1\", \"arg2\"\n      File \"/home/myself/repeated_test/example_options.py\", line 32, in _test\n        self.fail(\"example failure\")\n    AssertionError: example failure\n\n    ======================================================================\n    FAIL: test_overriding_one_value (example_options._test) (ham='ham2')\n    ----------------------------------------------------------------------\n    Traceback (most recent call last):\n      File \"/home/myself/repeated_test/example_options.py\", line 41, in MyFixtures\n        overriding_one_value = \"arg1\", \"arg2\"\n      File \"/home/myself/repeated_test/example_options.py\", line 32, in _test\n        self.fail(\"example failure\")\n    AssertionError: example failure\n\n.. _evaluated:\n\nEvaluated test case input\n-------------------------\n\nYou can use ``@evaluated`` to make\na function that can be inserted in a test case tuple.\nWhen running the test,\nthe function will be called,\nand the result will be spliced into the test case tuple:\n\n.. code-block:: python\n\n    from repeated_test import Fixtures, evaluated\n\n    class EvaluatedFixtures(Fixtures):\n        def _test(self, a, b, c):\n            pass\n\n        @evaluated\n        def fully_evaluated(self):\n            return (1 + 1, 2, 3)\n        # -> _test(2, 2, 3)\n\n        @evaluated\n        def _helper():\n            return (1 + 2, 3)\n        partly_evaluated = _helper(), 4\n        # -> _test(3, 3, 4)\n\nThe wrapped function must always return a tuple.\n\nThe wrapped function will also receive options as keyword arguments:\n\n.. code-block:: python\n\n    from repeated_test import Fixtures, evaluated, with_options_matrix\n\n    @with_options_matrix(\n        option=[\n            \"option 1\",\n            \"option 2\",\n        ],\n    )\n    class EvaluatedFixturesWithOptions(Fixtures):\n        def _test(self, a, *, option):\n            pass\n\n        @evaluated\n        def _helper(arg, *, option):\n            return (f\"{arg}-{option}\",)\n\n        using_option_in_evaluated = _helper(\"arg\")\n        # -> _test(\"arg-option 1\", option=\"option 1\")\n        # -> _test(\"arg-option 2\", option=\"option 2\")\n\n.. _named alternative:\n\nNamed alternatives\n------------------\n\nWhen using ``with_options_matrix``,\nsometimes the repr generated by those options is difficult to read.\nThis can be the case with functions,\nwhich can end up showing as something like\n``<function myfunc at 0x7f9f5e506280>``.\n\nYou can use ``NamedAlternative`` to give them a name:\n\n.. code-block:: python\n\n    from repeated_test import NamedAlternative\n\n    value1 = NamedAlternative(\"name for value1\", \"value1\")\n\n    @NamedAlternative(\"name for func1\")\n    def func1():\n        pass\n\n.. _naming:\n.. _escaping:\n\nNaming and escaping\n-------------------\n\nYou may name your test tuples however you like, though they may not start with\n``test_`` or ``_``. They are copied to the resulting |tc|_ class, and test\nmethods are created for them. Their name is that of the tuple, prefixed with\n``test_``.\n\n.. _regular test methods:\n.. _regular:\n\nMembers starting with ``test_`` or ``_`` are directly copied over to the\nresulting |tc|_ class, without being treated as fixtures. You can use this to\ninsert regular tests amongst your fixtures, or constants that you do not wish\nto be treated as tests:\n\n.. code-block:: python\n\n    from repeated_test import Fixtures\n\n    class MyFixtures(Fixtures):\n        def _test(self, arg1, arg2, arg3):\n            self.assertEqual(..., ...)\n\n        def test_other(self):\n            self.assertEqual(3, 1+2)\n\n        _spam = 'spam, bacon and eggs'\n        # _spam won't be treated as a fixture, so _test(*_spam) won't be called\n\n        ham = _spam, _spam, _spam\n\nYou may even call the test function using ``self._test(...)`` if necessary.\n\n\n.. _separate:\n\nSeparating tests and fixtures\n-----------------------------\n\nYou can apply a fixtures class to a different test function using its\n``with_test`` method:\n\n.. code-block:: python\n\n    class MyFixtures(Fixtures):\n        _test = None\n        ...\n\n    @MyFixtures.with_test\n    def other_test(self, arg1, arg2, arg3):\n        self.assertEqual(..., ...)\n\nWhile the function appears out of any class, it will be used as a method of\nthe resulting |tc|_ class, so keep in mind that it takes a ``self`` parameter.\n\nYou can reuse a fixture class however many times you like.\n\nIf you specify a test function this way, you can set ``_test = None``\nin your fixtures definition. However, it will not be discovered by |ut|_,\nso `regular test methods`_ won't be run.\nOmitting ``_test`` completely raises an error in order to prevent accidentally\ndisabling your tests.\n\n\n.. _decorator:\n\nWorking with functions as fixtures\n----------------------------------\n\nIt can be fairly impractical to use functions in your fixture tuples in this\nscheme. If your fixture tuple is meant to have one function in it, you can\nuse the ``tup`` decorator:\n\n.. code-block:: python\n\n    from repeated_test import Fixtures, tup\n\n    class my_tests(Fixtures):\n        def _test(self, func, arg1, arg2):\n            self.assertEqual(..., ...)\n\n        @tup('arg1', 'arg2')\n        def ham():\n            pass\n        # equivalent to\n        def _ham():\n            pass\n        ham = _ham, 'arg1', 'arg2'\n\n\n.. _non-unittest:\n\nReplacing |tc| with another class\n---------------------------------\n\nYou can replace |tc| with another class using ``WithTestClass(cls)``.\n\nFor instance, if you wish to use ``unittest2``:\n\n.. code-block:: python\n\n    import unittest2\n    from repeated_test import WithTestClass\n\n    class my_tests(WithTestClass(unittest2.TestCase)):\n        ...\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A quick unittest-compatible framework for repeating a test function over many fixtures",
    "version": "2.3.3",
    "project_urls": {
        "Homepage": "https://github.com/epsy/repeated_test"
    },
    "split_keywords": [
        "test",
        "testing",
        "unittest",
        "fixtures"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "6fc325590e565adea5263802aa01ed954c2f71234a049a8b495e66111134d0b2",
                "md5": "fbb02d8d723dfc66428b1104a0c581a5",
                "sha256": "0036c4103438304fdec107ec4a3eac83adc854c88f95b7fe3245e2296cbfdd13"
            },
            "downloads": -1,
            "filename": "repeated_test-2.3.3-py2.py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "fbb02d8d723dfc66428b1104a0c581a5",
            "packagetype": "bdist_wheel",
            "python_version": "py2.py3",
            "requires_python": ">=3.5",
            "size": 16186,
            "upload_time": "2023-07-18T07:02:03",
            "upload_time_iso_8601": "2023-07-18T07:02:03.835219Z",
            "url": "https://files.pythonhosted.org/packages/6f/c3/25590e565adea5263802aa01ed954c2f71234a049a8b495e66111134d0b2/repeated_test-2.3.3-py2.py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "99780911cdbd699c72701ba6755e7696d075bad52047ad6cd1e8976b08ded099",
                "md5": "510f38c9623e6b5dee2591ef4ecf915a",
                "sha256": "dd83d4f122fdaee779b34a67c301f94c9935317b0385d9039d9a7f3a3eac817b"
            },
            "downloads": -1,
            "filename": "repeated_test-2.3.3.tar.gz",
            "has_sig": false,
            "md5_digest": "510f38c9623e6b5dee2591ef4ecf915a",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.5",
            "size": 19107,
            "upload_time": "2023-07-18T07:02:05",
            "upload_time_iso_8601": "2023-07-18T07:02:05.125968Z",
            "url": "https://files.pythonhosted.org/packages/99/78/0911cdbd699c72701ba6755e7696d075bad52047ad6cd1e8976b08ded099/repeated_test-2.3.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-07-18 07:02:05",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "epsy",
    "github_project": "repeated_test",
    "travis_ci": true,
    "coveralls": true,
    "github_actions": true,
    "tox": true,
    "lcname": "repeated-test"
}
        
Elapsed time: 0.09164s