aboutsummaryrefslogtreecommitdiff
path: root/absl/testing/parameterized.py
diff options
context:
space:
mode:
Diffstat (limited to 'absl/testing/parameterized.py')
-rw-r--r--absl/testing/parameterized.py214
1 files changed, 110 insertions, 104 deletions
diff --git a/absl/testing/parameterized.py b/absl/testing/parameterized.py
index ec6a529..650d6cf 100644
--- a/absl/testing/parameterized.py
+++ b/absl/testing/parameterized.py
@@ -17,16 +17,15 @@
A parameterized test is a method in a test case that is invoked with different
argument tuples.
-A simple example:
-
- class AdditionExample(parameterized.TestCase):
- @parameterized.parameters(
- (1, 2, 3),
- (4, 5, 9),
- (1, 1, 3))
- def testAddition(self, op1, op2, result):
- self.assertEqual(result, op1 + op2)
+A simple example::
+ class AdditionExample(parameterized.TestCase):
+ @parameterized.parameters(
+ (1, 2, 3),
+ (4, 5, 9),
+ (1, 1, 3))
+ def testAddition(self, op1, op2, result):
+ self.assertEqual(result, op1 + op2)
Each invocation is a separate test case and properly isolated just
like a normal test method, with its own setUp/tearDown cycle. In the
@@ -34,15 +33,15 @@ example above, there are three separate testcases, one of which will
fail due to an assertion error (1 + 1 != 3).
Parameters for individual test cases can be tuples (with positional parameters)
-or dictionaries (with named parameters):
+or dictionaries (with named parameters)::
- class AdditionExample(parameterized.TestCase):
- @parameterized.parameters(
- {'op1': 1, 'op2': 2, 'result': 3},
- {'op1': 4, 'op2': 5, 'result': 9},
- )
- def testAddition(self, op1, op2, result):
- self.assertEqual(result, op1 + op2)
+ class AdditionExample(parameterized.TestCase):
+ @parameterized.parameters(
+ {'op1': 1, 'op2': 2, 'result': 3},
+ {'op1': 4, 'op2': 5, 'result': 9},
+ )
+ def testAddition(self, op1, op2, result):
+ self.assertEqual(result, op1 + op2)
If a parameterized test fails, the error message will show the
original test name and the parameters for that test.
@@ -50,129 +49,135 @@ original test name and the parameters for that test.
The id method of the test, used internally by the unittest framework, is also
modified to show the arguments (but note that the name reported by `id()`
doesn't match the actual test name, see below). To make sure that test names
-stay the same across several invocations, object representations like
+stay the same across several invocations, object representations like::
- >>> class Foo(object):
- ... pass
- >>> repr(Foo())
- '<__main__.Foo object at 0x23d8610>'
+ >>> class Foo(object):
+ ... pass
+ >>> repr(Foo())
+ '<__main__.Foo object at 0x23d8610>'
-are turned into '<__main__.Foo>'. When selecting a subset of test cases to run
+are turned into ``__main__.Foo``. When selecting a subset of test cases to run
on the command-line, the test cases contain an index suffix for each argument
-in the order they were passed to `parameters()` (eg. testAddition0,
+in the order they were passed to :func:`parameters` (eg. testAddition0,
testAddition1, etc.) This naming scheme is subject to change; for more reliable
-and stable names, especially in test logs, use `named_parameters()` instead.
+and stable names, especially in test logs, use :func:`named_parameters` instead.
-Tests using `named_parameters()` are similar to `parameters()`, except only
-tuples or dicts of args are supported. For tuples, the first parameter arg
+Tests using :func:`named_parameters` are similar to :func:`parameters`, except
+only tuples or dicts of args are supported. For tuples, the first parameter arg
has to be a string (or an object that returns an apt name when converted via
-str()). For dicts, a value for the key 'testcase_name' must be present and must
-be a string (or an object that returns an apt name when converted via str()):
-
- class NamedExample(parameterized.TestCase):
- @parameterized.named_parameters(
- ('Normal', 'aa', 'aaa', True),
- ('EmptyPrefix', '', 'abc', True),
- ('BothEmpty', '', '', True))
- def testStartsWith(self, prefix, string, result):
- self.assertEqual(result, string.startswith(prefix))
-
- class NamedExample(parameterized.TestCase):
- @parameterized.named_parameters(
- {'testcase_name': 'Normal',
- 'result': True, 'string': 'aaa', 'prefix': 'aa'},
- {'testcase_name': 'EmptyPrefix',
- 'result': True, 'string': 'abc', 'prefix': ''},
- {'testcase_name': 'BothEmpty',
- 'result': True, 'string': '', 'prefix': ''})
- def testStartsWith(self, prefix, string, result):
- self.assertEqual(result, string.startswith(prefix))
+``str()``). For dicts, a value for the key ``testcase_name`` must be present and
+must be a string (or an object that returns an apt name when converted via
+``str()``)::
+
+ class NamedExample(parameterized.TestCase):
+ @parameterized.named_parameters(
+ ('Normal', 'aa', 'aaa', True),
+ ('EmptyPrefix', '', 'abc', True),
+ ('BothEmpty', '', '', True))
+ def testStartsWith(self, prefix, string, result):
+ self.assertEqual(result, string.startswith(prefix))
+
+ class NamedExample(parameterized.TestCase):
+ @parameterized.named_parameters(
+ {'testcase_name': 'Normal',
+ 'result': True, 'string': 'aaa', 'prefix': 'aa'},
+ {'testcase_name': 'EmptyPrefix',
+ 'result': True, 'string': 'abc', 'prefix': ''},
+ {'testcase_name': 'BothEmpty',
+ 'result': True, 'string': '', 'prefix': ''})
+ def testStartsWith(self, prefix, string, result):
+ self.assertEqual(result, string.startswith(prefix))
Named tests also have the benefit that they can be run individually
-from the command line:
+from the command line::
- $ testmodule.py NamedExample.testStartsWithNormal
- .
- --------------------------------------------------------------------
- Ran 1 test in 0.000s
+ $ testmodule.py NamedExample.testStartsWithNormal
+ .
+ --------------------------------------------------------------------
+ Ran 1 test in 0.000s
- OK
+ OK
Parameterized Classes
=====================
+
If invocation arguments are shared across test methods in a single
TestCase class, instead of decorating all test methods
-individually, the class itself can be decorated:
+individually, the class itself can be decorated::
- @parameterized.parameters(
- (1, 2, 3),
- (4, 5, 9))
- class ArithmeticTest(parameterized.TestCase):
- def testAdd(self, arg1, arg2, result):
- self.assertEqual(arg1 + arg2, result)
+ @parameterized.parameters(
+ (1, 2, 3),
+ (4, 5, 9))
+ class ArithmeticTest(parameterized.TestCase):
+ def testAdd(self, arg1, arg2, result):
+ self.assertEqual(arg1 + arg2, result)
- def testSubtract(self, arg1, arg2, result):
- self.assertEqual(result - arg1, arg2)
+ def testSubtract(self, arg1, arg2, result):
+ self.assertEqual(result - arg1, arg2)
Inputs from Iterables
=====================
+
If parameters should be shared across several test cases, or are dynamically
created from other sources, a single non-tuple iterable can be passed into
-the decorator. This iterable will be used to obtain the test cases:
+the decorator. This iterable will be used to obtain the test cases::
- class AdditionExample(parameterized.TestCase):
- @parameterized.parameters(
- c.op1, c.op2, c.result for c in testcases
- )
- def testAddition(self, op1, op2, result):
- self.assertEqual(result, op1 + op2)
+ class AdditionExample(parameterized.TestCase):
+ @parameterized.parameters(
+ c.op1, c.op2, c.result for c in testcases
+ )
+ def testAddition(self, op1, op2, result):
+ self.assertEqual(result, op1 + op2)
Single-Argument Test Methods
============================
+
If a test method takes only one argument, the single arguments must not be
-wrapped into a tuple:
+wrapped into a tuple::
- class NegativeNumberExample(parameterized.TestCase):
- @parameterized.parameters(
- -1, -3, -4, -5
- )
- def testIsNegative(self, arg):
- self.assertTrue(IsNegative(arg))
+ class NegativeNumberExample(parameterized.TestCase):
+ @parameterized.parameters(
+ -1, -3, -4, -5
+ )
+ def testIsNegative(self, arg):
+ self.assertTrue(IsNegative(arg))
List/tuple as a Single Argument
===============================
+
If a test method takes a single argument of a list/tuple, it must be wrapped
-inside a tuple:
+inside a tuple::
- class ZeroSumExample(parameterized.TestCase):
- @parameterized.parameters(
- ([-1, 0, 1], ),
- ([-2, 0, 2], ),
- )
- def testSumIsZero(self, arg):
- self.assertEqual(0, sum(arg))
+ class ZeroSumExample(parameterized.TestCase):
+ @parameterized.parameters(
+ ([-1, 0, 1], ),
+ ([-2, 0, 2], ),
+ )
+ def testSumIsZero(self, arg):
+ self.assertEqual(0, sum(arg))
Cartesian product of Parameter Values as Parametrized Test Cases
-======================================================
+================================================================
+
If required to test method over a cartesian product of parameters,
`parameterized.product` may be used to facilitate generation of parameters
-test combinations:
+test combinations::
- class TestModuloExample(parameterized.TestCase):
- @parameterized.product(
- num=[0, 20, 80],
- modulo=[2, 4],
- expected=[0]
- )
- def testModuloResult(self, num, modulo, expected):
- self.assertEqual(expected, num % modulo)
+ class TestModuloExample(parameterized.TestCase):
+ @parameterized.product(
+ num=[0, 20, 80],
+ modulo=[2, 4],
+ expected=[0]
+ )
+ def testModuloResult(self, num, modulo, expected):
+ self.assertEqual(expected, num % modulo)
This results in 6 test cases being created - one for each combination of the
parameters. It is also possible to supply sequences of keyword argument dicts
-as elements of the cartesian product:
+as elements of the cartesian product::
@parameterized.product(
(dict(num=5, modulo=3, expected=2),
@@ -187,10 +192,11 @@ data (supplied as kwarg dicts) and for each of the two data types (supplied as
a named parameter). Multiple keyword argument dicts may be supplied if required.
Async Support
-===============================
+=============
+
If a test needs to call async functions, it can inherit from both
parameterized.TestCase and another TestCase that supports async calls, such
-as [asynctest](https://github.com/Martiusweb/asynctest):
+as [asynctest](https://github.com/Martiusweb/asynctest)::
import asynctest
@@ -674,16 +680,16 @@ def CoopTestCase(other_base_class): # pylint: disable=invalid-name
This enables the TestCase to be used in combination
with other base classes that have custom metaclasses, such as
- mox.MoxTestBase.
+ ``mox.MoxTestBase``.
- Only works with metaclasses that do not override type.__new__.
+ Only works with metaclasses that do not override ``type.__new__``.
- Example:
+ Example::
- from absl.testing import parameterized
+ from absl.testing import parameterized
- class ExampleTest(parameterized.CoopTestCase(OtherTestCase)):
- ...
+ class ExampleTest(parameterized.CoopTestCase(OtherTestCase)):
+ ...
Args:
other_base_class: (class) A test case base class.