allow to specify parametrize inputs as a comma-separated string

add Wouter to changelog and to authors
This commit is contained in:
holger krekel 2013-05-28 10:32:54 +02:00
parent bc5a5a63f2
commit c294a417bd
7 changed files with 71 additions and 27 deletions

View File

@ -7,6 +7,7 @@ Ronny Pfannschmidt
Benjamin Peterson
Floris Bruynooghe
Jason R. Coombs
Wouter van Ackooy
Samuele Pedroni
Brianna Laugher
Carl Friedrich Bolz

View File

@ -4,6 +4,13 @@ Changes between 2.3.5 and 2.4.DEV
- fix issue 308 - allow to mark/xfail/skip individual parameter sets
when parametrizing. Thanks Brianna Laugher.
- simplify parametrize() signature: allow to pass a CSV-separated string
to specify argnames. For example: ``pytest.mark.parametrize("input,expected", [(1,2), (2,3)])`` is possible now in addition to the prior
``pytest.mark.parametrize(("input", "expected"), ...)``.
- fix issue 306 - cleanup of -k/-m options to only match markers/test
names/keywords respectively. Thanks Wouter van Ackooy.
- (experimental) allow fixture functions to be
implemented as context managers. Thanks Andreas Pelme,
Vladimir Keleshev.

View File

@ -1,2 +1,2 @@
#
__version__ = '2.4.0.dev2'
__version__ = '2.4.0.dev3'

View File

@ -649,7 +649,8 @@ class Metafunc(FuncargnamesCompatAttr):
during the collection phase. If you need to setup expensive resources
see about setting indirect=True to do it rather at test setup time.
:arg argnames: an argument name or a list of argument names
:arg argnames: a comma-separated string denoting one or more argument
names, or a list/tuple of argument strings.
:arg argvalues: The list of argvalues determines how often a
test is invoked with different argument values. If only one
@ -688,7 +689,8 @@ class Metafunc(FuncargnamesCompatAttr):
argvalues = unwrapped_argvalues
if not isinstance(argnames, (tuple, list)):
argnames = (argnames,)
argnames = [x.strip() for x in argnames.split(",") if x.strip()]
if len(argnames) == 1:
argvalues = [(val,) for val in argvalues]
if not argvalues:
argvalues = [(_notexists,) * len(argnames)]

View File

@ -30,7 +30,7 @@ pytest supports test parametrization in several well-integrated ways:
.. regendoc: wipe
.. versionadded:: 2.2
.. versionadded:: 2.2, improved in 2.4
The builtin ``pytest.mark.parametrize`` decorator enables
parametrization of arguments for a test function. Here is a typical example
@ -39,7 +39,7 @@ to an expected output::
# content of test_expectation.py
import pytest
@pytest.mark.parametrize(("input", "expected"), [
@pytest.mark.parametrize("input,expected", [
("3+5", 8),
("2+4", 6),
("6*9", 42),
@ -47,23 +47,24 @@ to an expected output::
def test_eval(input, expected):
assert eval(input) == expected
Here, the ``@parametrize`` decorator defines three different argument
sets for the two ``(input, output)`` arguments of the ``test_eval`` function
which will thus run three times::
Here, the ``@parametrize`` decorator defines three different ``(input,output)``
tuples so that that the ``test_eval`` function will run three times using
them in turn::
$ py.test
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- pytest-2.3.5
============================= test session starts ==============================
platform linux2 -- Python 2.7.3 -- pytest-2.4.0.dev3
plugins: xdist, cache, cli, pep8, xprocess, cov, capturelog, bdd-splinter, rerunfailures, instafail, localserver
collected 3 items
test_expectation.py ..F
================================= FAILURES =================================
____________________________ test_eval[6*9-42] _____________________________
=================================== FAILURES ===================================
______________________________ test_eval[6*9-42] _______________________________
input = '6*9', expected = 42
@pytest.mark.parametrize(("input", "expected"), [
@pytest.mark.parametrize("input,expected", [
("3+5", 8),
("2+4", 6),
("6*9", 42),
@ -74,19 +75,21 @@ which will thus run three times::
E + where 54 = eval('6*9')
test_expectation.py:8: AssertionError
==================== 1 failed, 2 passed in 0.01 seconds ====================
====================== 1 failed, 2 passed in 0.02 seconds ======================
As expected only one pair of input/output values fails the simple test function.
And as usual with test function arguments, you can see the ``input`` and ``output`` values in the traceback.
As designed in this example, only one pair of input/output values fails
the simple test function. And as usual with test function arguments,
you can see the ``input`` and ``output`` values in the traceback.
Note that there ways how you can mark a class or a module,
see :ref:`mark`.
Note that you could also use the parametrize marker on a class or a module
(see :ref:`mark`) which would invoke several functions with the argument sets.
It is also possible to mark individual test instances within parametrize::
It is also possible to mark individual test instances within parametrize,
for example with the builtin ``mark.xfail``::
# content of test_expectation.py
import pytest
@pytest.mark.parametrize(("input", "expected"), [
@pytest.mark.parametrize("input,expected", [
("3+5", 8),
("2+4", 6),
pytest.mark.xfail(("6*9", 42)),
@ -94,6 +97,27 @@ It is also possible to mark individual test instances within parametrize::
def test_eval(input, expected):
assert eval(input) == expected
Let's run this::
$ py.test
============================= test session starts ==============================
platform linux2 -- Python 2.7.3 -- pytest-2.4.0.dev3
plugins: xdist, cache, cli, pep8, xprocess, cov, capturelog, bdd-splinter, rerunfailures, instafail, localserver
collected 3 items
test_expectation.py ..x
===================== 2 passed, 1 xfailed in 0.02 seconds ======================
The one parameter set which caused a failure previously now
shows up as an "xfailed (expected to fail)" test.
.. note::
In versions prior to 2.4 one needed to specify the argument
names as a tuple. This remains valid but the simpler ``"name1,name2,..."``
comma-separated-string syntax is now advertised fist because
it's easier to write, produces less line noise.
.. _`pytest_generate_tests`:
@ -140,15 +164,15 @@ Let's also run with a stringinput that will lead to a failing test::
$ py.test -q --stringinput="!" test_strings.py
F
================================= FAILURES =================================
___________________________ test_valid_string[!] ___________________________
=================================== FAILURES ===================================
_____________________________ test_valid_string[!] _____________________________
stringinput = '!'
def test_valid_string(stringinput):
> assert stringinput.isalpha()
E assert <built-in method isalpha of str object at 0x2ba729dab300>()
E + where <built-in method isalpha of str object at 0x2ba729dab300> = '!'.isalpha
E assert <built-in method isalpha of str object at 0x7fd657390fd0>()
E + where <built-in method isalpha of str object at 0x7fd657390fd0> = '!'.isalpha
test_strings.py:3: AssertionError
@ -160,8 +184,8 @@ listlist::
$ py.test -q -rs test_strings.py
s
========================= short test summary info ==========================
SKIP [1] /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/python.py:974: got empty parameter set, function test_valid_string at /tmp/doc-exec-240/test_strings.py:1
=========================== short test summary info ============================
SKIP [1] /home/hpk/p/pytest/_pytest/python.py:999: got empty parameter set, function test_valid_string at /tmp/doc-exec-2/test_strings.py:1
For further examples, you might want to look at :ref:`more
parametrization examples <paramexamples>`.

View File

@ -12,7 +12,7 @@ def main():
name='pytest',
description='py.test: simple powerful testing with Python',
long_description = long_description,
version='2.4.0.dev2',
version='2.4.0.dev3',
url='http://pytest.org',
license='MIT license',
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],

View File

@ -221,6 +221,16 @@ class TestMetafunc:
"*6 fail*",
])
def test_parametrize_CSV(self, testdir):
testdir.makepyfile("""
import pytest
@pytest.mark.parametrize("x, y,", [(1,2), (2,3)])
def test_func(x, y):
assert x+1 == y
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=2)
def test_parametrize_class_scenarios(self, testdir):
testdir.makepyfile("""
# same as doc/en/example/parametrize scenario example