Parameterized
Parameterized is a Python library that provides parameterized testing capabilities for various test frameworks like unittest, pytest, and nose. It simplifies writing data-driven tests by allowing the same test logic to be run with multiple sets of input data, reducing duplication and improving test coverage. The current version is 0.9.0, released in March 2023.
Common errors
-
AttributeError: 'function' object has no attribute 'expand'
cause This error typically occurs when the incorrect package `parametrized` (missing the 'e') is installed instead of the correct `parameterized` library.fixUninstall the wrong package (`pip uninstall parametrized`) and install the correct one (`pip install parameterized`). -
ImportError: cannot import name 'parameterized_class'
cause This happens when `parameterized_class` is not directly exposed for import from the top-level `parameterized` package, or due to an older version of the library not exposing it directly.fixEnsure you are using a recent version of the library (0.9.0 or later) and import it as `from parameterized import parameterized_class`. If the issue persists, explicitly import from the submodule `from parameterized.parameterized import parameterized_class` if the library structure changed or you are on an older version. -
ModuleNotFoundError: No module named 'parameterized'
cause The `parameterized` library is not installed in the Python environment being used.fixInstall the library using pip: `pip install parameterized`. -
UnboundLocalError: local variable 'patching' referenced before assignment
cause This error often arises when combining `@parameterized.expand` with `unittest.mock.patch` decorators and their order is incorrect, as the `patch` decorator must come *below* `parameterized.expand` to function properly.fixEnsure that the `@mock.patch(...)` decorator is placed *below* the `@parameterized.expand(...)` decorator. Also, the mocked parameters must come last in the test method's signature.
Warnings
- breaking As of version 0.9.0, `parameterized` has dropped support for Python 2.x, 3.5, and 3.6. If you require these Python versions, you must use an older version of `parameterized` (e.g., 0.8.1).
- gotcha When combining `@parameterized` (or `@parameterized.expand`) with `@mock.patch`, the `@mock.patch` decorator must be placed *below* the `@parameterized` decorator. Additionally, the arguments introduced by `mock.patch` should appear *last* in the test method's signature. Incorrect ordering can lead to unexpected behavior or errors.
- gotcha If you use an iterator or generator to supply parameters to `@parameterized` or `@parameterized.expand`, all items will be loaded into memory *before* the test run begins. This can be a significant memory concern for very large or infinite parameter sets.
- gotcha A common pitfall is installing `parametrized` (missing the 'e') instead of `parameterized`. This will result in an `AttributeError: 'function' object has no attribute 'expand'` when trying to use `parameterized.expand`.
- gotcha Overcomplicating parameterized test cases with excessive parameters or too many variations within a single test can lead to confusion, difficulty in maintenance, and unclear results. This defeats the purpose of parameterized testing.
- breaking Using `@parameterized` directly on a test method within a `unittest.TestCase` subclass will raise an exception. The library explicitly requires `@parameterized.expand` for parameterizing methods within `TestCase` subclasses.
- breaking Using the `@parameterized` decorator directly on a `unittest.TestCase` subclass will raise an `Exception`. The `@parameterized` decorator is designed for non-TestCase functions or classes. For parameterizing individual test methods within a `unittest.TestCase` subclass, you must use `@parameterized.expand`.
Install
-
pip install parameterized
Imports
- parameterized
from parametrized import parameterized
from parameterized import parameterized
- param
from parameterized import param
- parameterized_class
from parameterized import parameterized_class
Quickstart
import unittest
from parameterized import parameterized, param
import math
class TestMath(unittest.TestCase):
@parameterized([
(2, 2, 4),
(2, 3, 8),
(1, 9, 1),
(0, 9, 0),
])
def test_pow(self, base, exponent, expected):
self.assertEqual(math.pow(base, exponent), expected)
@parameterized.expand([
("negative", -1.5, -2.0),
("integer", 1, 1.0),
("large fraction", 1.6, 1),
])
def test_floor(self, name, input_val, expected):
self.assertEqual(math.floor(input_val), expected)
@parameterized_class(('a', 'b', 'expected_sum'), [
(1, 2, 3),
(5, 5, 10),
])
class TestMathClass(unittest.TestCase):
def test_add(self):
self.assertEqual(self.a + self.b, self.expected_sum)
# To run these tests, you would typically use:
# unittest.main(argv=['first-arg-is-ignored'], exit=False)
# or a test runner like pytest/nose.