From dc55551213a7e55fb7de7ff1d59ea9ba124f6514 Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Fri, 24 Jun 2016 12:08:57 +0200 Subject: [PATCH 01/10] Start proposal for parametrize with fixtures --- doc/en/parametrize_with_fixtures.rst | 58 ++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 doc/en/parametrize_with_fixtures.rst diff --git a/doc/en/parametrize_with_fixtures.rst b/doc/en/parametrize_with_fixtures.rst new file mode 100644 index 00000000000..06cfea5e393 --- /dev/null +++ b/doc/en/parametrize_with_fixtures.rst @@ -0,0 +1,58 @@ +========================= +Parametrize with fixtures +========================= + +Problem +------- + +As a user I have functional tests that I would like to run against various +scenarios. + +In this particular example we want to generate a new project based on a +cookiecutter template. We want to test default values but also data that +emulates user input. + +- use default values +- emulate user input + - specify 'author' + - specify 'project_slug' + - specify 'author' and 'project_slug' + +This is how a functional test could look like: + +.. code-block:: python + + import pytest + + @pytest.fixture + def default_context(): + return {'extra_context': {}} + + + @pytest.fixture(params=[ + {'author': 'alice'}, + {'project_slug': 'helloworld'}, + {'author': 'bob', 'project_slug': 'foobar'}, + ]) + def extra_context(request): + return {'extra_context': request.param} + + + @pytest.fixture(params=['default', 'extra']) + def context(request): + if request.param == 'default': + return request.getfuncargvalue('default_context') + else: + return request.getfuncargvalue('extra_context') + + + def test_generate_project(cookies, context): + """Call the cookiecutter API to generate a new project from a + template. + """ + result = cookies.bake(extra_context=context) + + assert result.exit_code == 0 + assert result.exception is None + assert result.project.isdir() + From 84f0dcecf8c6001d6fe3785378160722ceb74ff3 Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Sat, 25 Jun 2016 10:10:57 +0200 Subject: [PATCH 02/10] Add issues section to proposal doc --- doc/en/parametrize_with_fixtures.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/doc/en/parametrize_with_fixtures.rst b/doc/en/parametrize_with_fixtures.rst index 06cfea5e393..e18887a6403 100644 --- a/doc/en/parametrize_with_fixtures.rst +++ b/doc/en/parametrize_with_fixtures.rst @@ -56,3 +56,21 @@ This is how a functional test could look like: assert result.exception is None assert result.project.isdir() + +Issues +------ + +* By using ``request.getfuncargvalue()`` we rely on actual fixture function + execution to know what fixtures are involved, due to it's dynamic nature +* More importantly, ``request.getfuncargvalue()`` cannot be combined with + parametrized fixtures, such as ``extra_context`` +* This is very inconvenient if you wish to extend an existing test suite by + certain parameters for fixtures that are already used by tests + +pytest version 3.0 and higher reports an error if you try to run above code:: + + Failed: The requested fixture has no parameter defined for the current + test. + + Requested fixture 'extra_context' + From c6a711c2fce7259fb2b36a247771843bbf7c626d Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Sat, 25 Jun 2016 10:50:14 +0200 Subject: [PATCH 03/10] Add proposed solution using a module function --- doc/en/parametrize_with_fixtures.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/doc/en/parametrize_with_fixtures.rst b/doc/en/parametrize_with_fixtures.rst index e18887a6403..4b6f21c0392 100644 --- a/doc/en/parametrize_with_fixtures.rst +++ b/doc/en/parametrize_with_fixtures.rst @@ -74,3 +74,19 @@ pytest version 3.0 and higher reports an error if you try to run above code:: Requested fixture 'extra_context' + +Proposed solution +----------------- + +A new function that can be used in modules can be used to dynamically define +fixtures from existing ones. + +.. code-block:: python + + pytest.define_combined_fixture( + name='context', + fixtures=['default_context', 'extra_context'], + ) + +The new fixture ``context`` inherits the scope from the used fixtures. + From 4f8b8c8d312f659ab3c453df31ee05c5c2645728 Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Sat, 25 Jun 2016 10:55:08 +0200 Subject: [PATCH 04/10] Add alternative approach that uses wrappers --- doc/en/parametrize_with_fixtures.rst | 48 ++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/doc/en/parametrize_with_fixtures.rst b/doc/en/parametrize_with_fixtures.rst index 4b6f21c0392..3964d9d7ded 100644 --- a/doc/en/parametrize_with_fixtures.rst +++ b/doc/en/parametrize_with_fixtures.rst @@ -90,3 +90,51 @@ fixtures from existing ones. The new fixture ``context`` inherits the scope from the used fixtures. +Alternative approach +-------------------- + +A new helper function named ``fixture_request`` tells pytest to yield all +parameters of a fixture. + +.. code-block:: python + + @pytest.fixture(params=[ + pytest.fixture_request('default_context'), + pytest.fixture_request('extra_context'), + ]) + def context(request): + """Returns all values for ``default_context``, one-by-one before it + does the same for ``extra_context``. + + request.param: + - {} + - {'author': 'alice'} + - {'project_slug': 'helloworld'} + - {'author': 'bob', 'project_slug': 'foobar'} + """ + return request.param + +.. note:: + + How should the scoping work in that case? Ideally it uses invocation scope + and relies on its params + +The same helper can be used in combination with ``pytest.mark.parametrize``. + +.. code-block:: python + + + @pytest.mark.parametrize( + 'context, expected_response_code', + [ + (pytest.fixture_request('default_context'), 0), + (pytest.fixture_request('extra_context'), 0), + ], + ) + def test_generate_project(cookies, context, exit_code): + """Call the cookiecutter API to generate a new project from a + template. + """ + result = cookies.bake(extra_context=context) + + assert result.exit_code == exit_code From 693859210a24d3ba58b5ab93e91d0eb53e9eb872 Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Sat, 25 Jun 2016 11:00:54 +0200 Subject: [PATCH 05/10] Add yielded values to function example --- doc/en/parametrize_with_fixtures.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/doc/en/parametrize_with_fixtures.rst b/doc/en/parametrize_with_fixtures.rst index 3964d9d7ded..762f1d8a4a7 100644 --- a/doc/en/parametrize_with_fixtures.rst +++ b/doc/en/parametrize_with_fixtures.rst @@ -88,7 +88,13 @@ fixtures from existing ones. fixtures=['default_context', 'extra_context'], ) -The new fixture ``context`` inherits the scope from the used fixtures. +The new fixture ``context`` inherits the scope from the used fixtures and yield +the following values. + +- ``{}`` +- ``{'author': 'alice'}`` +- ``{'project_slug': 'helloworld'}`` +- ``{'author': 'bob', 'project_slug': 'foobar'}`` Alternative approach -------------------- From 526c564576d641ffdef12654fca6d63dc8f66ebc Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Sat, 25 Jun 2016 11:06:17 +0200 Subject: [PATCH 06/10] Fix rst bullet point lists --- doc/en/parametrize_with_fixtures.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/en/parametrize_with_fixtures.rst b/doc/en/parametrize_with_fixtures.rst index 762f1d8a4a7..d65e5eb1560 100644 --- a/doc/en/parametrize_with_fixtures.rst +++ b/doc/en/parametrize_with_fixtures.rst @@ -13,9 +13,13 @@ cookiecutter template. We want to test default values but also data that emulates user input. - use default values + - emulate user input + - specify 'author' + - specify 'project_slug' + - specify 'author' and 'project_slug' This is how a functional test could look like: @@ -92,8 +96,11 @@ The new fixture ``context`` inherits the scope from the used fixtures and yield the following values. - ``{}`` + - ``{'author': 'alice'}`` + - ``{'project_slug': 'helloworld'}`` + - ``{'author': 'bob', 'project_slug': 'foobar'}`` Alternative approach From 5860c609aeafa2fc2cf6b449fa83903c87fbc6af Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Sat, 25 Jun 2016 11:09:46 +0200 Subject: [PATCH 07/10] Remove note on scoping --- doc/en/parametrize_with_fixtures.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/doc/en/parametrize_with_fixtures.rst b/doc/en/parametrize_with_fixtures.rst index d65e5eb1560..ab3ffecf0d1 100644 --- a/doc/en/parametrize_with_fixtures.rst +++ b/doc/en/parametrize_with_fixtures.rst @@ -127,11 +127,6 @@ parameters of a fixture. """ return request.param -.. note:: - - How should the scoping work in that case? Ideally it uses invocation scope - and relies on its params - The same helper can be used in combination with ``pytest.mark.parametrize``. .. code-block:: python From acfdd85dffa8ddbf61ad4ad987980dd265a8c5e9 Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Sat, 25 Jun 2016 14:42:19 +0200 Subject: [PATCH 08/10] Move document to proposals subfolder --- doc/en/{ => proposals}/parametrize_with_fixtures.rst | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename doc/en/{ => proposals}/parametrize_with_fixtures.rst (100%) diff --git a/doc/en/parametrize_with_fixtures.rst b/doc/en/proposals/parametrize_with_fixtures.rst similarity index 100% rename from doc/en/parametrize_with_fixtures.rst rename to doc/en/proposals/parametrize_with_fixtures.rst From eb98a8eefbe959dace13c809e03715bf0c2f4914 Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Sat, 25 Jun 2016 14:52:57 +0200 Subject: [PATCH 09/10] Change version in issues section to pytest 3.0 only --- doc/en/proposals/parametrize_with_fixtures.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/en/proposals/parametrize_with_fixtures.rst b/doc/en/proposals/parametrize_with_fixtures.rst index ab3ffecf0d1..e8c31d0d809 100644 --- a/doc/en/proposals/parametrize_with_fixtures.rst +++ b/doc/en/proposals/parametrize_with_fixtures.rst @@ -71,7 +71,7 @@ Issues * This is very inconvenient if you wish to extend an existing test suite by certain parameters for fixtures that are already used by tests -pytest version 3.0 and higher reports an error if you try to run above code:: +pytest version 3.0 reports an error if you try to run above code:: Failed: The requested fixture has no parameter defined for the current test. From 1b6bc4d606a98d88b332a5e380af64ac92c2d610 Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Sat, 25 Jun 2016 14:58:18 +0200 Subject: [PATCH 10/10] Add feature proposal to changelog --- CHANGELOG.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d95d66384ed..01c214ca6e5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -106,6 +106,9 @@ Thanks `@Vogtinator`_ for reporting. Thanks to `@RedBeardCode`_ and `@tomviner`_ for PR. +* Add proposal to docs for a new feature that enables users to combine multiple + fixtures into one. Thanks to `@hpk42`_ and `@hackebrot`_. + * .. _#1580: https://github.com/pytest-dev/pytest/pull/1580