diff --git a/AUTHORS b/AUTHORS index 8cfa17f00..8dfc8e58e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -7,6 +7,7 @@ Ronny Pfannschmidt Benjamin Peterson Floris Bruynooghe Jason R. Coombs +Wouter van Ackooy Samuele Pedroni Brianna Laugher Carl Friedrich Bolz diff --git a/CHANGELOG b/CHANGELOG index d561c8088..9b63f95ed 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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. diff --git a/_pytest/__init__.py b/_pytest/__init__.py index 9695ad68a..a5d89a853 100644 --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '2.4.0.dev2' +__version__ = '2.4.0.dev3' diff --git a/_pytest/python.py b/_pytest/python.py index 1327fe1af..3dcc0836f 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -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)] diff --git a/doc/en/parametrize.txt b/doc/en/parametrize.txt index 779cef60e..5c326d0b2 100644 --- a/doc/en/parametrize.txt +++ b/doc/en/parametrize.txt @@ -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 () - E + where = '!'.isalpha + E assert () + E + where = '!'.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 `. diff --git a/setup.py b/setup.py index 883bc2d63..538d267ce 100644 --- a/setup.py +++ b/setup.py @@ -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'], diff --git a/testing/python/metafunc.py b/testing/python/metafunc.py index ccc1b2f22..71438870a 100644 --- a/testing/python/metafunc.py +++ b/testing/python/metafunc.py @@ -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