Skip to main content

Decorator for parameterized testing with Nose

Project description

Now with 100% less Python 3 incompatibility!

Nose. It’s got test generators. But they kind of suck:

  • They often require a second function

  • They make it difficult to separate the data from the test

  • They don’t work with subclases of unittest.TestCase

  • kwargs? What kwargs?

But nose-parameterized fixes that:

# test_math.py
from nose.tools import assert_equal
from nose_parameterized import parameterized

import unittest
import math

@parameterized([
    (2, 2, 4),
    (2, 3, 8),
    (1, 9, 1),
    (0, 9, 0),
])
def test_pow(base, exponent, expected):
    assert_equal(math.pow(base, exponent), expected)

class TestMathUnitTest(unittest.TestCase):
    @parameterized.expand([
        ("negative", -1.5, -2.0),
        ("integer", 1, 1.0),
        ("large fraction", 1.6, 1),
    ])
    def test_floor(self, name, input, expected):
        assert_equal(math.floor(input), expected)
$ nosetests -v test_math.py
test_math.test_pow(2, 2, 4) ... ok
test_math.test_pow(2, 3, 8) ... ok
test_math.test_pow(1, 9, 1) ... ok
test_math.test_pow(0, 9, 0) ... ok
test_floor_0_negative (test_math.TestMathUnitTest) ... ok
test_floor_1_integer (test_math.TestMathUnitTest) ... ok
test_floor_2_large_fraction (test_math.TestMathUnitTest) ... ok

----------------------------------------------------------------------
Ran 7 tests in 0.002s

OK

Exhaustive Usage Examples

The @parameterized and @parameterized.expand decorators accept a list or iterable of tuples or param(...), or a callable which returns a list or iterable:

from nose_parameterized import parameterized, param

# A list of tuples
@parameterized([
    (2, 3, 5),
    (3, 5, 8),
])
def test_add(a, b, expected):
    assert_equal(a + b, expected)

# A list of params
@parameterized([
    param("10", 10),
    param("10", 16, base=16),
])
def test_int(str_val, expected, base=10):
    assert_equal(int(str_val, base=base), expected)

# An iterable of params
@parameterized(
    param.explicit(*json.loads(line))
    for line in open("testcases.jsons")
)
def test_from_json_file(...):
    ...

# A callable which returns a list of tuples
def load_test_cases():
    return [
        ("test1", ),
        ("test2", ),
    ]
@parameterized(load_test_cases)
def test_from_function(name):
    ...

Note that, when using an iterator or a generator, Nose will read every item into memory before running any tests (as it first finds and loads every test in each test file, then executes all of them at once).

The @parameterized decorator can be used test class methods, and standalone functions:

from nose_parameterized import parameterized

class AddTest(object):
    @parameterized([
        (2, 3, 5),
    ])
    def test_add(self, a, b, expected):
        assert_equal(a + b, expected)

@parameterized([
    (2, 3, 5),
])
def test_add(a, b, expected):
    assert_equal(a + b, expected)

And @parameterized.expand can be used to generate test methods in situations where test generators cannot be used (for example, when the test class is a subclass of unittest.TestCase):

import unittest
from nose_parameterized import parameterized

class AddTestCase(unittest.TestCase):
    @parameterized.expand([
        ("2 and 3", 2, 3, 5),
        ("3 and 5", 2, 3, 5),
    ])
    def test_add(self, _, a, b, expected):
        assert_equal(a + b, expected)

Will create the test cases:

$ nosetests example.py
test_add_0_2_and_3 (example.AddTestCase) ... ok
test_add_1_3_and_5 (example.AddTestCase) ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK

Note that @parameterized.expand works by creating new methods on the test class. If the first parameter is a string, that string will be added to the end of the method name. For example, the test case above will generate the methods test_add_0_2_and_3 and test_add_1_3_and_5.

The names of the test cases generated by @parameterized.expand can be customized using the testcase_func_name keyword argument. The value should be a function which accepts three arguments: testcase_func, param_num, and params, and it should return the name of the test case. testcase_func will be the function to be tested, param_num will be the index of the test case parameters in the list of parameters, and param (an instance of param) will be the parameters which will be used.

import unittest
from nose_parameterized import parameterized

def custom_name_func(testcase_func, param_num, param):
    return "%s_%s" %(
        testcase_func.__name__,
        parameterized.to_safe_name("_".join(str(x) for x in param.args)),
    )

class AddTestCase(unittest.TestCase):
    @parameterized.expand([
        (2, 3, 5),
        (2, 3, 5),
    ], testcase_func_name=custom_name_func)
    def test_add(self, a, b, expected):
        assert_equal(a + b, expected)

Will create the test cases:

$ nosetests example.py
test_add_1_2_3 (example.AddTestCase) ... ok
test_add_2_3_5 (example.AddTestCase) ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK

The param(...) helper class stores the parameters for one specific test case. It can be used to pass keyword arguments to test cases:

from nose_parameterized import parameterized, param

@parameterized([
    param("10", 10),
    param("10", 16, base=16),
])
def test_int(str_val, expected, base=10):
    assert_equal(int(str_val, base=base), expected)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nose-parameterized-0.4.2.tar.gz (8.2 kB view details)

Uploaded Source

Built Distribution

nose_parameterized-0.4.2-py2.py3-none-any.whl (9.0 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file nose-parameterized-0.4.2.tar.gz.

File metadata

File hashes

Hashes for nose-parameterized-0.4.2.tar.gz
Algorithm Hash digest
SHA256 85209f6819f1f2ebd4256adb82b0f5886b405705fd7630d880463798b7dd8958
MD5 228de0307c6b93d93d9d2597ca72224d
BLAKE2b-256 6d08ab88eed4e71f36f1f122c7483b5b938bde06f453f0a91ae423521405a7e7

See more details on using hashes here.

File details

Details for the file nose_parameterized-0.4.2-py2.py3-none-any.whl.

File metadata

File hashes

Hashes for nose_parameterized-0.4.2-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 da1729985ee970b8b304e63115f128688cb798a176980269d195ce19fe3ca74e
MD5 9d4b9a668e5e79f0df600578f3881e3e
BLAKE2b-256 db3ef704762b38c0dd9ecc32398b118affd532c82267e5023b7d700091daa376

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page