.. |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"
}