diff --git a/HISTORY.rst b/HISTORY.rst index c50549c..128473e 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -7,6 +7,8 @@ Release History **Features and Improvements** - Cover Python 3.9 and 3.10 and Django 3.2, drop Python 3.5 and Django 3.0 support +- Bump Behave requirement to 1.2.7 (allows option to change the Behave TestRunner) +- New option to change the Django TestRunner 1.4.0 (2020-06-15) ++++++++++++++++++ diff --git a/behave_django/management/commands/behave.py b/behave_django/management/commands/behave.py index 2182d96..998aa0a 100644 --- a/behave_django/management/commands/behave.py +++ b/behave_django/management/commands/behave.py @@ -4,6 +4,7 @@ from behave.__main__ import main as behave_main from behave.configuration import options as behave_options +from behave.configuration import valid_python_module from django.core.management.base import BaseCommand from behave_django.environment import monkey_patch_behave @@ -54,6 +55,14 @@ def add_command_arguments(parser): help="Use simple test runner that supports Django's" " testing client only (no web browser automation)" ) + parser.add_argument( + '--runner-class', + action='store', + type=valid_python_module, + default='behave_django.runner.BehaviorDrivenTestRunner', + help=('Full Python dotted path to a package, module, Django ' + 'TestRunner. Defaults to "%(default)s)".') + ) def add_behave_arguments(parser): # noqa @@ -70,6 +79,7 @@ def add_behave_arguments(parser): # noqa '-v', '-S', '--simple', + '--runner-class', ] parser.add_argument( @@ -120,6 +130,9 @@ def add_arguments(self, parser): def handle(self, *args, **options): + django_runner_class = options['runner_class'] + is_default_runner = django_runner_class is BehaviorDrivenTestRunner + # Check the flags if options['use_existing_database'] and options['simple']: self.stderr.write(self.style.WARNING( @@ -127,6 +140,13 @@ def handle(self, *args, **options): ' together with --use-existing-database' )) + active_flags = options['use_existing_database'] or options['simple'] + if not is_default_runner and active_flags: + self.stderr.write(self.style.WARNING( + '--use-existing-database or --simple has no effect' + ' together with --runner-class' + )) + # Configure django environment passthru_args = ('failfast', 'interactive', @@ -136,13 +156,13 @@ def handle(self, *args, **options): k, v in options.items() if k in passthru_args and v is not None} - if options['dry_run'] or options['use_existing_database']: - django_test_runner = ExistingDatabaseTestRunner(**runner_args) - elif options['simple']: - django_test_runner = SimpleTestRunner(**runner_args) - else: - django_test_runner = BehaviorDrivenTestRunner(**runner_args) + if is_default_runner: + if options['dry_run'] or options['use_existing_database']: + django_runner_class = ExistingDatabaseTestRunner + elif options['simple']: + django_runner_class = SimpleTestRunner + django_test_runner = django_runner_class(**runner_args) django_test_runner.setup_test_environment() old_config = django_test_runner.setup_databases() diff --git a/docs/conf.py b/docs/conf.py index a7c7bc7..c08f12e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -12,9 +12,9 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys import os import shlex +import sys sys.path.insert(0, os.path.abspath('..')) diff --git a/docs/configuration.rst b/docs/configuration.rst index c4d9421..b04b0b9 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -13,14 +13,6 @@ management command. Additional command line options provided by *behave-django*: -``--use-existing-database`` -*************************** - -Don't create a test database, and use the database of your default runserver -instead. USE AT YOUR OWN RISK! Only use this option for testing against a -*copy* of your production database or other valuable data. Your tests may -destroy your data irrecoverably. - ``--keepdb`` ************ @@ -30,6 +22,15 @@ recreating it each time you run the test. This flag enables ``manage.py behave --keepdb`` to take advantage of that feature. |keepdb docs|_. +``--runner-class`` +****************** + +Full Python dotted path to a package, module, Django TestRunner. + +Not to be confused with `--behave-runner-class` that handles the internal +`TestRunner` inside `behave`. You can read more about it in the +`behave docs `__. + ``--simple`` ************ @@ -38,6 +39,14 @@ after each scenario instead of flushing the entire database. Tests run much quicker, however HTTP server is not started and therefore web browser automation is not available. +``--use-existing-database`` +*************************** + +Don't create a test database, and use the database of your default runserver +instead. USE AT YOUR OWN RISK! Only use this option for testing against a +*copy* of your production database or other valuable data. Your tests may +destroy your data irrecoverably. + Behave configuration file ------------------------- diff --git a/requirements.txt b/requirements.txt index fd5cc61..2d75887 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ beautifulsoup4 -behave +behave@git+http://github.com/behave/behave.git@v1.2.7.dev2#egg=behave # behave>=1.2.7 django>=2.2 diff --git a/setup.py b/setup.py index e485b0f..d5bdfdb 100755 --- a/setup.py +++ b/setup.py @@ -4,6 +4,7 @@ """ from os import chdir from os.path import abspath, dirname, normpath + from setuptools import find_packages, setup # allow setup.py to be run from any path diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py index db37508..7deed25 100644 --- a/tests/unit/test_cli.py +++ b/tests/unit/test_cli.py @@ -1,6 +1,8 @@ import os from imp import reload +import pytest + from .util import DjangoSetupMixin, run_silently, show_run_error @@ -15,6 +17,7 @@ def test_additional_management_command_options(self): os.linesep) in output assert (os.linesep + ' -k, --keepdb') in output assert (os.linesep + ' -S, --simple') in output + assert (os.linesep + ' --runner-class') in output assert (os.linesep + ' --noinput, --no-input') in output assert (os.linesep + ' --failfast') in output assert (os.linesep + ' -r, --reverse') in output @@ -22,14 +25,20 @@ def test_additional_management_command_options(self): def test_should_accept_behave_arguments(self): from behave_django.management.commands.behave import Command command = Command() - args = command.get_behave_args( - argv=['manage.py', 'behave', - '--format', 'progress', - '--settings', 'test_project.settings', - '-i', 'some-pattern', - 'features/running-tests.feature']) + argv = [ + 'manage.py', 'behave', + '--format', 'progress', + '--behave-runner-class', 'behave.runner.Runner', + '--runner-class', 'behave_django.runner.BehaviorDrivenTestRunner', + '--settings', 'test_project.settings', + '-i', 'some-pattern', + 'features/running-tests.feature' + ] + args = command.get_behave_args(argv=argv) assert '--format' in args + assert '--runner-class' in args + assert args[args.index('--runner-class') + 1] == 'behave.runner.Runner' assert 'progress' in args assert '-i' in args assert 'some-pattern' in args @@ -107,3 +116,65 @@ def test_simple_and_use_existing_database_flags_raise_a_warning(self): '--simple flag has no effect together with ' '--use-existing-database' + os.linesep) in output + + @pytest.mark.parametrize('arguments, expect_error', [ + ( + '--runner-class behave_django.runner.BehaviorDrivenTestRunner', + False + ), + ( + ( + '--runner-class behave_django.runner.SimpleTestRunner ' + '--simple' + ), + True + ), + ( + ( + '--runner-class behave_django.runner.BehaviorDrivenTestRunner ' + '--simple' + ), + False + ), + ( + ( + '--behave-runner-class behave.runner.Runner ' + '--runner-class behave_django.runner.SimpleTestRunner ' + '--simple' + ), + True + ), + ( + ( + '--runner-class behave_django.runner.SimpleTestRunner ' + '--use-existing-database' + ), + True + ), + ('--behave-runner-class behave.runner.Runner --simple', False), + ( + ( + '--behave-runner-class behave.runner.Runner ' + '--runner-class behave_django.runner.BehaviorDrivenTestRunner' + ), + False + ), + ]) + def test_runner_class_and_others_flags_raise_a_warning(self, arguments, + expect_error): + exit_status, output = run_silently( + 'python tests/manage.py behave' + ' %s --tags=@skip-all' % arguments + ) + assert exit_status == 0, \ + show_run_error(exit_status, output) + + warning_message = ( + os.linesep + + '--use-existing-database or --simple has no effect' + ' together with --runner-class' + + os.linesep) + if expect_error: + assert warning_message in output + else: + assert warning_message not in output diff --git a/tests/unit/test_passthru_args.py b/tests/unit/test_passthru_args.py index 65f97d9..bfb3594 100644 --- a/tests/unit/test_passthru_args.py +++ b/tests/unit/test_passthru_args.py @@ -4,7 +4,7 @@ @mock.patch('behave_django.management.commands.behave.behave_main', return_value=0) # noqa -@mock.patch('behave_django.management.commands.behave.BehaviorDrivenTestRunner') # noqa +@mock.patch('behave_django.runner.BehaviorDrivenTestRunner') class TestPassThruArgs(DjangoSetupMixin): def test_keepdb_flag(self,