From: DongHun Kwak Date: Mon, 12 Apr 2021 06:19:14 +0000 (+0900) Subject: Imported Upstream version python3-pytest-repeat 0.8.0 X-Git-Tag: upstream/0.8.0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fheads%2Fupstream;p=platform%2Fupstream%2Fpython3-pytest-repeat.git Imported Upstream version python3-pytest-repeat 0.8.0 --- 9a6812ed496ed3c7ba571849edb77d528fb3624a diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..274da80 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,34 @@ +language: python +python: +- 2.7 +- 3.4 +- 3.5 +- 3.6 +- pypy +- pypy3 +- nightly +env: +- TOXENV=pytest36 +- TOXENV=pytest37 +- TOXENV=pytest38 +matrix: + include: + - python: 2.7 + env: TOXENV=flake8 + - python: 3.5 + env: TOXENV=flake8 +install: +- pip install tox-travis +script: +- tox +deploy: + provider: pypi + user: davehunt + password: + secure: IuoBL03YKh7rZw78aQqRrlD6YcvwSPK6nKTpoxFc3uiljOufyfV3s4rGffSxEl4gAkMlBz3SXnfPKJPqNizfp3TEJXrc84TBO/Iq+U7j43rWyUluzJ0okPgU4892aalQiEvVyrrjEaMWA5ndhX7tkyTICN0BfHlKPmMrN+1mq73y4eUQl49CJWsbhF8Qnc5tcDh2athtgFA3fG0kSWDZHdw02i2JC1qlm+WvqBfw813BeUnmR55HKRgPQMJ2whUzab7m2QBg0HkjniNXaqS+aYY8fMGrntNtEDRrWO130ioeUqpFQvg7FoigbE5eQBX07Z50lpJn5CuCgnMzOrDpkXMy7Y+k+MyxKFUWaaqZjZiKolaPSs2qW5zggmCD4ECa5g8BpfpBkUj+D6iFkYyZIJUdq2jX0JFA536L9H2E1KOATxE8u0utQvkKcJhHgWVa0iw0q14MWSVLcZ8OdzP0Bo5nVVICcZAyIj7FQn0pIRnoXQ7cIpGbmMeJUBT9n08hyUYWoxfXKNt8KNkKDww81nAVphuz6ic1KwEKIDt3MJlHHbazjt59/+SBU+L0bDhS5ZHZkHAVHyl3EP18DCAYZWJjR4TZxlLRb2o3BUTcSwqFcIlTGw1O1DbZ/LTaGRRUxwh41AY98DKxrujxerALgX3MIlaS6WkM1FbOdO+ZB1Q= + distributions: sdist bdist_wheel + on: + tags: true + repo: pytest-dev/pytest-repeat + python: 3.5 + condition: "$TOXENV = pytest38" diff --git a/CHANGES.rst b/CHANGES.rst new file mode 100644 index 0000000..0e3d759 --- /dev/null +++ b/CHANGES.rst @@ -0,0 +1,49 @@ +Release Notes +------------- + +**0.8.0 (2019-02-26)** + +* Fix mark deprecation warnings in new pytest versions. + +* ``pytest-repeat`` now requires pytest>=3.6. + +**0.7.0 (2018-08-23)** + +* Move step number to the end of the parametrisation ID + + * Thanks to `@gdyuldin `_ for suggesting + this enhancement and providing a patch + +**0.6.0 (2018-08-01)** + +* Add option for controlling the scope of the repeat parameterisation + + * Thanks to `@gdyuldin `_ for suggesting + this enhancement and providing a patch + +**0.5.0 (2018-07-19)** + +* Allow repeating a test using a decorator (`#16 `_) + + * Thanks to `@Peque `_ for suggesting + this enhancement and providing a patch + +**0.4.0 (2016-08-25)** + +* No changes - testing deploy to PyPI from Travis CI + +**0.4.0 (2016-08-09)** + +* Fix deprecation warning present in pytest 3.0 for type argument in addoption + +**0.3.0 (2016-06-30)** + +* Added support for repeating parameterised tests + +**0.2 (2015-10-27)** + +* README updates + +**0.1 (2015-10-19)** + +* Initial release diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1e55f5d --- /dev/null +++ b/LICENSE @@ -0,0 +1,3 @@ +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at https://www.mozilla.org/en-US/MPL/2.0/. diff --git a/PKG-INFO b/PKG-INFO new file mode 100644 index 0000000..2143105 --- /dev/null +++ b/PKG-INFO @@ -0,0 +1,123 @@ +Metadata-Version: 1.1 +Name: pytest-repeat +Version: 0.8.0 +Summary: pytest plugin for repeating tests +Home-page: https://github.com/pytest-dev/pytest-repeat +Author: Bob Silverberg +Author-email: bsilverberg@mozilla.com +License: Mozilla Public License 2.0 (MPL 2.0) +Description: pytest-repeat + =================== + + pytest-repeat is a plugin for `py.test `_ that makes it + easy to repeat a single test, or multiple tests, a specific number of times. + + .. image:: https://img.shields.io/badge/license-MPL%202.0-blue.svg + :target: https://github.com/pytest-dev/pytest-repeat/blob/master/LICENSE + :alt: License + .. image:: https://img.shields.io/pypi/v/pytest-repeat.svg + :target: https://pypi.python.org/pypi/pytest-repeat/ + :alt: PyPI + .. image:: https://img.shields.io/travis/pytest-dev/pytest-repeat.svg + :target: https://travis-ci.org/pytest-dev/pytest-repeat/ + :alt: Travis + .. image:: https://img.shields.io/github/issues-raw/pytest-dev/pytest-repeat.svg + :target: https://github.com/pytest-dev/pytest-repeat/issues + :alt: Issues + .. image:: https://img.shields.io/requires/github/pytest-dev/pytest-repeat.svg + :target: https://requires.io/github/pytest-dev/pytest-repeat/requirements/?branch=master + :alt: Requirements + + Requirements + ------------ + + You will need the following prerequisites in order to use pytest-repeat: + + - Python 2.7, 3.4+ or PyPy + - py.test 2.8 or newer + + Installation + ------------ + To install pytest-repeat: + + .. code-block:: bash + + $ pip install pytest-repeat + + Repeating a test + ---------------- + + Use the :code:`--count` command line option to specify how many times you want + your test, or tests, to be run: + + .. code-block:: bash + + $ py.test --count=10 test_file.py + + Each test collected by py.test will be run :code:`count` times. + + If you want to mark a test in your code to be repeated a number of times, you + can use the :code:`@pytest.mark.repeat(count)` decorator: + + .. code-block:: python + + import pytest + + + @pytest.mark.repeat(3) + def test_repeat_decorator(): + pass + + If you want to override default tests executions order, you can use :code:`--repeat-scope` + command line option with one of the next values: :code:`session`, :code:`module`, :code:`class` or :code:`function` (default). + It behaves like a scope of the pytest fixture. + + :code:`function` (default) scope repeats each test :code:`count` or :code:`repeat` times before executing next test. + :code:`session` scope repeats whole tests session, i.e. all collected tests executed once, then all such tests executed again and etc. + :code:`class` and :code:`module` behaves similar :code:`session` , but repeating set of tests is a tests from class or module, not all collected tests. + + Repeating a test until failure + ------------------------------ + + If you are trying to diagnose an intermittent failure, it can be useful to run the same + test over and over again until it fails. You can use pytest's :code:`-x` option in + conjunction with pytest-repeat to force the test runner to stop at the first failure. + For example: + + .. code-block:: bash + + $ py.test --count=1000 -x test_file.py + + This will attempt to run test_file.py 1000 times, but will stop as soon as a failure + occurs. + + UnitTest Style Tests + -------------------- + + Unfortunately pytest-repeat is not able to work with unittest.TestCase test classes. + These tests will simply always run once, regardless of :code:`--count`, and show a warning. + + Resources + --------- + + - `Release Notes `_ + - `Issue Tracker `_ + - `Code `_ + +Keywords: py.test pytest repeat +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Framework :: Pytest +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) +Classifier: Operating System :: POSIX +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Topic :: Software Development :: Quality Assurance +Classifier: Topic :: Software Development :: Testing +Classifier: Topic :: Utilities +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..73293eb --- /dev/null +++ b/README.rst @@ -0,0 +1,97 @@ +pytest-repeat +=================== + +pytest-repeat is a plugin for `py.test `_ that makes it +easy to repeat a single test, or multiple tests, a specific number of times. + +.. image:: https://img.shields.io/badge/license-MPL%202.0-blue.svg + :target: https://github.com/pytest-dev/pytest-repeat/blob/master/LICENSE + :alt: License +.. image:: https://img.shields.io/pypi/v/pytest-repeat.svg + :target: https://pypi.python.org/pypi/pytest-repeat/ + :alt: PyPI +.. image:: https://img.shields.io/travis/pytest-dev/pytest-repeat.svg + :target: https://travis-ci.org/pytest-dev/pytest-repeat/ + :alt: Travis +.. image:: https://img.shields.io/github/issues-raw/pytest-dev/pytest-repeat.svg + :target: https://github.com/pytest-dev/pytest-repeat/issues + :alt: Issues +.. image:: https://img.shields.io/requires/github/pytest-dev/pytest-repeat.svg + :target: https://requires.io/github/pytest-dev/pytest-repeat/requirements/?branch=master + :alt: Requirements + +Requirements +------------ + +You will need the following prerequisites in order to use pytest-repeat: + +- Python 2.7, 3.4+ or PyPy +- py.test 2.8 or newer + +Installation +------------ +To install pytest-repeat: + +.. code-block:: bash + + $ pip install pytest-repeat + +Repeating a test +---------------- + +Use the :code:`--count` command line option to specify how many times you want +your test, or tests, to be run: + +.. code-block:: bash + + $ py.test --count=10 test_file.py + +Each test collected by py.test will be run :code:`count` times. + +If you want to mark a test in your code to be repeated a number of times, you +can use the :code:`@pytest.mark.repeat(count)` decorator: + +.. code-block:: python + + import pytest + + + @pytest.mark.repeat(3) + def test_repeat_decorator(): + pass + +If you want to override default tests executions order, you can use :code:`--repeat-scope` +command line option with one of the next values: :code:`session`, :code:`module`, :code:`class` or :code:`function` (default). +It behaves like a scope of the pytest fixture. + +:code:`function` (default) scope repeats each test :code:`count` or :code:`repeat` times before executing next test. +:code:`session` scope repeats whole tests session, i.e. all collected tests executed once, then all such tests executed again and etc. +:code:`class` and :code:`module` behaves similar :code:`session` , but repeating set of tests is a tests from class or module, not all collected tests. + +Repeating a test until failure +------------------------------ + +If you are trying to diagnose an intermittent failure, it can be useful to run the same +test over and over again until it fails. You can use pytest's :code:`-x` option in +conjunction with pytest-repeat to force the test runner to stop at the first failure. +For example: + +.. code-block:: bash + + $ py.test --count=1000 -x test_file.py + +This will attempt to run test_file.py 1000 times, but will stop as soon as a failure +occurs. + +UnitTest Style Tests +-------------------- + +Unfortunately pytest-repeat is not able to work with unittest.TestCase test classes. +These tests will simply always run once, regardless of :code:`--count`, and show a warning. + +Resources +--------- + +- `Release Notes `_ +- `Issue Tracker `_ +- `Code `_ diff --git a/pytest_repeat.egg-info/PKG-INFO b/pytest_repeat.egg-info/PKG-INFO new file mode 100644 index 0000000..2143105 --- /dev/null +++ b/pytest_repeat.egg-info/PKG-INFO @@ -0,0 +1,123 @@ +Metadata-Version: 1.1 +Name: pytest-repeat +Version: 0.8.0 +Summary: pytest plugin for repeating tests +Home-page: https://github.com/pytest-dev/pytest-repeat +Author: Bob Silverberg +Author-email: bsilverberg@mozilla.com +License: Mozilla Public License 2.0 (MPL 2.0) +Description: pytest-repeat + =================== + + pytest-repeat is a plugin for `py.test `_ that makes it + easy to repeat a single test, or multiple tests, a specific number of times. + + .. image:: https://img.shields.io/badge/license-MPL%202.0-blue.svg + :target: https://github.com/pytest-dev/pytest-repeat/blob/master/LICENSE + :alt: License + .. image:: https://img.shields.io/pypi/v/pytest-repeat.svg + :target: https://pypi.python.org/pypi/pytest-repeat/ + :alt: PyPI + .. image:: https://img.shields.io/travis/pytest-dev/pytest-repeat.svg + :target: https://travis-ci.org/pytest-dev/pytest-repeat/ + :alt: Travis + .. image:: https://img.shields.io/github/issues-raw/pytest-dev/pytest-repeat.svg + :target: https://github.com/pytest-dev/pytest-repeat/issues + :alt: Issues + .. image:: https://img.shields.io/requires/github/pytest-dev/pytest-repeat.svg + :target: https://requires.io/github/pytest-dev/pytest-repeat/requirements/?branch=master + :alt: Requirements + + Requirements + ------------ + + You will need the following prerequisites in order to use pytest-repeat: + + - Python 2.7, 3.4+ or PyPy + - py.test 2.8 or newer + + Installation + ------------ + To install pytest-repeat: + + .. code-block:: bash + + $ pip install pytest-repeat + + Repeating a test + ---------------- + + Use the :code:`--count` command line option to specify how many times you want + your test, or tests, to be run: + + .. code-block:: bash + + $ py.test --count=10 test_file.py + + Each test collected by py.test will be run :code:`count` times. + + If you want to mark a test in your code to be repeated a number of times, you + can use the :code:`@pytest.mark.repeat(count)` decorator: + + .. code-block:: python + + import pytest + + + @pytest.mark.repeat(3) + def test_repeat_decorator(): + pass + + If you want to override default tests executions order, you can use :code:`--repeat-scope` + command line option with one of the next values: :code:`session`, :code:`module`, :code:`class` or :code:`function` (default). + It behaves like a scope of the pytest fixture. + + :code:`function` (default) scope repeats each test :code:`count` or :code:`repeat` times before executing next test. + :code:`session` scope repeats whole tests session, i.e. all collected tests executed once, then all such tests executed again and etc. + :code:`class` and :code:`module` behaves similar :code:`session` , but repeating set of tests is a tests from class or module, not all collected tests. + + Repeating a test until failure + ------------------------------ + + If you are trying to diagnose an intermittent failure, it can be useful to run the same + test over and over again until it fails. You can use pytest's :code:`-x` option in + conjunction with pytest-repeat to force the test runner to stop at the first failure. + For example: + + .. code-block:: bash + + $ py.test --count=1000 -x test_file.py + + This will attempt to run test_file.py 1000 times, but will stop as soon as a failure + occurs. + + UnitTest Style Tests + -------------------- + + Unfortunately pytest-repeat is not able to work with unittest.TestCase test classes. + These tests will simply always run once, regardless of :code:`--count`, and show a warning. + + Resources + --------- + + - `Release Notes `_ + - `Issue Tracker `_ + - `Code `_ + +Keywords: py.test pytest repeat +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Framework :: Pytest +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) +Classifier: Operating System :: POSIX +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Topic :: Software Development :: Quality Assurance +Classifier: Topic :: Software Development :: Testing +Classifier: Topic :: Utilities +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 diff --git a/pytest_repeat.egg-info/SOURCES.txt b/pytest_repeat.egg-info/SOURCES.txt new file mode 100644 index 0000000..277de5f --- /dev/null +++ b/pytest_repeat.egg-info/SOURCES.txt @@ -0,0 +1,16 @@ +.gitignore +.travis.yml +CHANGES.rst +LICENSE +README.rst +pytest_repeat.py +setup.cfg +setup.py +test_repeat.py +tox.ini +pytest_repeat.egg-info/PKG-INFO +pytest_repeat.egg-info/SOURCES.txt +pytest_repeat.egg-info/dependency_links.txt +pytest_repeat.egg-info/entry_points.txt +pytest_repeat.egg-info/requires.txt +pytest_repeat.egg-info/top_level.txt \ No newline at end of file diff --git a/pytest_repeat.egg-info/dependency_links.txt b/pytest_repeat.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/pytest_repeat.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/pytest_repeat.egg-info/entry_points.txt b/pytest_repeat.egg-info/entry_points.txt new file mode 100644 index 0000000..400d7c5 --- /dev/null +++ b/pytest_repeat.egg-info/entry_points.txt @@ -0,0 +1,3 @@ +[pytest11] +repeat = pytest_repeat + diff --git a/pytest_repeat.egg-info/requires.txt b/pytest_repeat.egg-info/requires.txt new file mode 100644 index 0000000..d2940d2 --- /dev/null +++ b/pytest_repeat.egg-info/requires.txt @@ -0,0 +1 @@ +pytest>=3.6 diff --git a/pytest_repeat.egg-info/top_level.txt b/pytest_repeat.egg-info/top_level.txt new file mode 100644 index 0000000..da63fdb --- /dev/null +++ b/pytest_repeat.egg-info/top_level.txt @@ -0,0 +1 @@ +pytest_repeat diff --git a/pytest_repeat.py b/pytest_repeat.py new file mode 100644 index 0000000..411b7f7 --- /dev/null +++ b/pytest_repeat.py @@ -0,0 +1,70 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://www.mozilla.org/en-US/MPL/2.0/. +import warnings +from unittest import TestCase + +import pytest + + +def pytest_addoption(parser): + parser.addoption( + '--count', + action='store', + default=1, + type=int, + help='Number of times to repeat each test') + + parser.addoption( + '--repeat-scope', + action='store', + default='function', + type=str, + choices=('function', 'class', 'module', 'session'), + help='Scope for repeating tests') + + +def pytest_configure(config): + config.addinivalue_line( + 'markers', + 'repeat(n): run the given test function `n` times.') + + +class UnexpectedError(Exception): + pass + + +@pytest.fixture(autouse=True) +def __pytest_repeat_step_number(request): + if request.config.option.count > 1: + try: + return request.param + except AttributeError: + if issubclass(request.cls, TestCase): + warnings.warn( + "Repeating unittest class tests not supported") + else: + raise UnexpectedError( + "This call couldn't work with pytest-repeat. " + "Please consider raising an issue with your usage.") + + +@pytest.hookimpl(trylast=True) +def pytest_generate_tests(metafunc): + count = metafunc.config.option.count + m = metafunc.definition.get_closest_marker('repeat') + if m is not None: + count = int(m.args[0]) + if count > 1: + + def make_progress_id(i, n=count): + return '{0}-{1}'.format(i + 1, n) + + scope = metafunc.config.option.repeat_scope + metafunc.parametrize( + '__pytest_repeat_step_number', + range(count), + indirect=True, + ids=make_progress_id, + scope=scope + ) diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..adf5ed7 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,7 @@ +[bdist_wheel] +universal = 1 + +[egg_info] +tag_build = +tag_date = 0 + diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..3e42eab --- /dev/null +++ b/setup.py @@ -0,0 +1,31 @@ +from setuptools import setup + +setup(name='pytest-repeat', + use_scm_version=True, + description='pytest plugin for repeating tests', + long_description=open('README.rst').read(), + author='Bob Silverberg', + author_email='bsilverberg@mozilla.com', + url='https://github.com/pytest-dev/pytest-repeat', + py_modules=['pytest_repeat'], + entry_points={'pytest11': ['repeat = pytest_repeat']}, + setup_requires=['setuptools_scm'], + install_requires=['pytest>=3.6'], + license='Mozilla Public License 2.0 (MPL 2.0)', + keywords='py.test pytest repeat', + classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Framework :: Pytest', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)', + 'Operating System :: POSIX', + 'Operating System :: Microsoft :: Windows', + 'Operating System :: MacOS :: MacOS X', + 'Topic :: Software Development :: Quality Assurance', + 'Topic :: Software Development :: Testing', + 'Topic :: Utilities', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6']) diff --git a/test_repeat.py b/test_repeat.py new file mode 100644 index 0000000..220ccc1 --- /dev/null +++ b/test_repeat.py @@ -0,0 +1,259 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://www.mozilla.org/en-US/MPL/2.0/. + +import pytest + +pytest_plugins = "pytester", + + +class TestRepeat: + + def test_no_repeat(self, testdir): + testdir.makepyfile(""" + def test_no_repeat(): + pass + """) + result = testdir.runpytest('-v', '--count', '1') + result.stdout.fnmatch_lines([ + '*test_no_repeat.py::test_no_repeat PASSED*', + '*1 passed*', + ]) + assert result.ret == 0 + + def test_can_repeat(self, testdir): + testdir.makepyfile(""" + def test_repeat(): + pass + """) + result = testdir.runpytest('--count', '2') + result.stdout.fnmatch_lines(['*2 passed*']) + assert result.ret == 0 + + def test_mark_repeat_decorator_is_registered(self, testdir): + result = testdir.runpytest('--markers') + result.stdout.fnmatch_lines([ + '@pytest.mark.repeat(n): run the given test function `n` times.']) + assert result.ret == 0 + + def test_mark_repeat_decorator(self, testdir): + testdir.makepyfile(""" + import pytest + @pytest.mark.repeat(3) + def test_mark_repeat_decorator(): + pass + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines(['*3 passed*']) + assert result.ret == 0 + + def test_parametrize(self, testdir): + testdir.makepyfile(""" + import pytest + @pytest.mark.parametrize('x', ['a', 'b', 'c']) + def test_repeat(x): + pass + """) + result = testdir.runpytest('-v', '--count', '2') + result.stdout.fnmatch_lines([ + '*test_parametrize.py::test_repeat[[]a-1-2[]] PASSED*', + '*test_parametrize.py::test_repeat[[]a-2-2[]] PASSED*', + '*test_parametrize.py::test_repeat[[]b-1-2[]] PASSED*', + '*test_parametrize.py::test_repeat[[]b-2-2[]] PASSED*', + '*test_parametrize.py::test_repeat[[]c-1-2[]] PASSED*', + '*test_parametrize.py::test_repeat[[]c-2-2[]] PASSED*', + '*6 passed*', + ]) + assert result.ret == 0 + + def test_parametrized_fixture(self, testdir): + testdir.makepyfile(""" + import pytest + @pytest.fixture(params=['a', 'b', 'c']) + def parametrized_fixture(request): + return request.param + + def test_repeat(parametrized_fixture): + pass + """) + result = testdir.runpytest('--count', '2') + result.stdout.fnmatch_lines(['*6 passed*']) + assert result.ret == 0 + + def test_step_number(self, testdir): + testdir.makepyfile(""" + import pytest + expected_steps = iter(range(5)) + def test_repeat(__pytest_repeat_step_number): + assert next(expected_steps) == __pytest_repeat_step_number + if __pytest_repeat_step_number == 4: + assert not list(expected_steps) + """) + result = testdir.runpytest('-v', '--count', '5') + result.stdout.fnmatch_lines([ + '*test_step_number.py::test_repeat[[]1-5[]] PASSED*', + '*test_step_number.py::test_repeat[[]2-5[]] PASSED*', + '*test_step_number.py::test_repeat[[]3-5[]] PASSED*', + '*test_step_number.py::test_repeat[[]4-5[]] PASSED*', + '*test_step_number.py::test_repeat[[]5-5[]] PASSED*', + '*5 passed*', + ]) + assert result.ret == 0 + + def test_invalid_option(self, testdir): + testdir.makepyfile(""" + def test_repeat(): + pass + """) + result = testdir.runpytest('--count', 'a') + assert result.ret == 4 + + def test_unittest_test(self, testdir): + testdir.makepyfile(""" + from unittest import TestCase + + class ClassStyleTest(TestCase): + def test_this(self): + assert 1 + """) + result = testdir.runpytest('-v', '--count', '2') + result.stdout.fnmatch_lines([ + '*test_unittest_test.py::ClassStyleTest::test_this PASSED*', + '*1 passed*', + ]) + + @pytest.mark.parametrize(['scope', 'lines'], [ + ('session', [ + '*test_1.py::test_repeat1[[]1-2[]] PASSED*', + '*test_1.py::test_repeat2[[]1-2[]] PASSED*', + '*test_2.py::test_repeat3[[]1-2[]] PASSED*', + '*test_2.py::test_repeat4[[]1-2[]] PASSED*', + '*test_3.py::TestRepeat1::test_repeat5[[]1-2[]] PASSED*', + '*test_3.py::TestRepeat1::test_repeat6[[]1-2[]] PASSED*', + '*test_3.py::TestRepeat2::test_repeat7[[]1-2[]] PASSED*', + '*test_3.py::TestRepeat2::test_repeat8[[]1-2[]] PASSED*', + '*test_1.py::test_repeat1[[]2-2[]] PASSED*', + '*test_1.py::test_repeat2[[]2-2[]] PASSED*', + '*test_2.py::test_repeat3[[]2-2[]] PASSED*', + '*test_2.py::test_repeat4[[]2-2[]] PASSED*', + '*test_3.py::TestRepeat1::test_repeat5[[]2-2[]] PASSED*', + '*test_3.py::TestRepeat1::test_repeat6[[]2-2[]] PASSED*', + '*test_3.py::TestRepeat2::test_repeat7[[]2-2[]] PASSED*', + '*test_3.py::TestRepeat2::test_repeat8[[]2-2[]] PASSED*', + '*16 passed*', + ]), + ('module', [ + '*test_1.py::test_repeat1[[]1-2[]] PASSED*', + '*test_1.py::test_repeat2[[]1-2[]] PASSED*', + '*test_1.py::test_repeat1[[]2-2[]] PASSED*', + '*test_1.py::test_repeat2[[]2-2[]] PASSED*', + '*test_2.py::test_repeat3[[]1-2[]] PASSED*', + '*test_2.py::test_repeat4[[]1-2[]] PASSED*', + '*test_2.py::test_repeat3[[]2-2[]] PASSED*', + '*test_2.py::test_repeat4[[]2-2[]] PASSED*', + '*test_3.py::TestRepeat1::test_repeat5[[]1-2[]] PASSED*', + '*test_3.py::TestRepeat1::test_repeat6[[]1-2[]] PASSED*', + '*test_3.py::TestRepeat2::test_repeat7[[]1-2[]] PASSED*', + '*test_3.py::TestRepeat2::test_repeat8[[]1-2[]] PASSED*', + '*test_3.py::TestRepeat1::test_repeat5[[]2-2[]] PASSED*', + '*test_3.py::TestRepeat1::test_repeat6[[]2-2[]] PASSED*', + '*test_3.py::TestRepeat2::test_repeat7[[]2-2[]] PASSED*', + '*test_3.py::TestRepeat2::test_repeat8[[]2-2[]] PASSED*', + '*16 passed*', + ]), + ('class', [ + '*test_1.py::test_repeat1[[]1-2[]] PASSED*', + '*test_1.py::test_repeat2[[]1-2[]] PASSED*', + '*test_1.py::test_repeat1[[]2-2[]] PASSED*', + '*test_1.py::test_repeat2[[]2-2[]] PASSED*', + '*test_2.py::test_repeat3[[]1-2[]] PASSED*', + '*test_2.py::test_repeat4[[]1-2[]] PASSED*', + '*test_2.py::test_repeat3[[]2-2[]] PASSED*', + '*test_2.py::test_repeat4[[]2-2[]] PASSED*', + '*test_3.py::TestRepeat1::test_repeat5[[]1-2[]] PASSED*', + '*test_3.py::TestRepeat1::test_repeat6[[]1-2[]] PASSED*', + '*test_3.py::TestRepeat1::test_repeat5[[]2-2[]] PASSED*', + '*test_3.py::TestRepeat1::test_repeat6[[]2-2[]] PASSED*', + '*test_3.py::TestRepeat2::test_repeat7[[]1-2[]] PASSED*', + '*test_3.py::TestRepeat2::test_repeat8[[]1-2[]] PASSED*', + '*test_3.py::TestRepeat2::test_repeat7[[]2-2[]] PASSED*', + '*test_3.py::TestRepeat2::test_repeat8[[]2-2[]] PASSED*', + '*16 passed*', + ]), + ('function', [ + '*test_1.py::test_repeat1[[]1-2[]] PASSED*', + '*test_1.py::test_repeat1[[]2-2[]] PASSED*', + '*test_1.py::test_repeat2[[]1-2[]] PASSED*', + '*test_1.py::test_repeat2[[]2-2[]] PASSED*', + '*test_2.py::test_repeat3[[]1-2[]] PASSED*', + '*test_2.py::test_repeat3[[]2-2[]] PASSED*', + '*test_2.py::test_repeat4[[]1-2[]] PASSED*', + '*test_2.py::test_repeat4[[]2-2[]] PASSED*', + '*test_3.py::TestRepeat1::test_repeat5[[]1-2[]] PASSED*', + '*test_3.py::TestRepeat1::test_repeat5[[]2-2[]] PASSED*', + '*test_3.py::TestRepeat1::test_repeat6[[]1-2[]] PASSED*', + '*test_3.py::TestRepeat1::test_repeat6[[]2-2[]] PASSED*', + '*test_3.py::TestRepeat2::test_repeat7[[]1-2[]] PASSED*', + '*test_3.py::TestRepeat2::test_repeat7[[]2-2[]] PASSED*', + '*test_3.py::TestRepeat2::test_repeat8[[]1-2[]] PASSED*', + '*test_3.py::TestRepeat2::test_repeat8[[]2-2[]] PASSED*', + '*16 passed*', + ]), + ]) + def test_scope(self, testdir, scope, lines): + testdir.makepyfile(test_1=""" + def test_repeat1(): + pass + + def test_repeat2(): + pass + """) + testdir.makepyfile(test_2=""" + def test_repeat3(): + pass + + def test_repeat4(): + pass + """) + testdir.makepyfile(test_3=""" + class TestRepeat1(object): + def test_repeat5(self): + pass + def test_repeat6(self): + pass + class TestRepeat2(object): + def test_repeat7(self): + pass + def test_repeat8(self): + pass + """) + result = testdir.runpytest('-v', '--count', '2', '--repeat-scope', + scope) + result.stdout.fnmatch_lines(lines) + assert result.ret == 0 + + def test_omitted_scope(self, testdir): + testdir.makepyfile(""" + def test_repeat1(): + pass + + def test_repeat2(): + pass + """) + result = testdir.runpytest('-v', '--count', '2') + result.stdout.fnmatch_lines([ + '*test_omitted_scope.py::test_repeat1[[]1-2[]] PASSED*', + '*test_omitted_scope.py::test_repeat1[[]2-2[]] PASSED*', + '*test_omitted_scope.py::test_repeat2[[]1-2[]] PASSED*', + '*test_omitted_scope.py::test_repeat2[[]2-2[]] PASSED*', + '*4 passed*', + ]) + assert result.ret == 0 + + def test_invalid_scope(self, testdir): + testdir.makepyfile(""" + def test_repeat(): + pass + """) + result = testdir.runpytest('--count', '2', '--repeat-scope', 'a') + assert result.ret == 4 diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..9c59b9a --- /dev/null +++ b/tox.ini @@ -0,0 +1,19 @@ +# Tox (https://tox.readthedocs.io/) is a tool for running tests +# in multiple virtualenvs. This configuration file will run the +# test suite on all supported python versions. To use it, "pip install tox" +# and then run "tox" from this directory. + +[tox] +envlist = py{27,34,35,36,py,py3}-pytest{36,37,38}, flake8 + +[testenv] +commands = pytest {posargs} +deps = + pytest36: pytest~=3.6 + pytest37: pytest~=3.7 + pytest38: pytest~=3.8 + +[testenv:flake8] +basepython = python +deps = flake8 +commands = flake8 {posargs:pytest_repeat.py test_repeat.py}