How to run behave-django features in PyCharm?

1k views Asked by At

Background

I have a Django project ("api") with unittest tests and behave features. Relevant parts of its structure are

code/ # i.e. the Django root is not the root of the project
    manage.py
    api/
        settings.py
        # and other Django stuff
    app/
        # Django app stuff
    features/
        environment.py
        steps/
        foo.feature
    virtualenv/

I use behave-django. python manage.py behave works.

I use PyCharm. It's configured to use the project's virtualenv. Its Django support is configured thus:

enter image description here

Running Django and running unittest tests inside PyCharm works.

The problem

When I attempt to run a behave feature in PyCharm (by hitting control-shift-R when editing the feature file and choosing the behave run context configuration) I get

/Users/dave/data/projects/api/code/virtualenv/bin/python2.7 "/Applications/PyCharm 2016.3.app/Contents/helpers/pycharm/behave_runner.py"
Testing started at 04:31 ...
Traceback (most recent call last):
  File "/Applications/PyCharm 2016.3.app/Contents/helpers/pycharm/behave_runner.py", line 294, in <module>
    _BehaveRunner(my_config, base_dir).run()
  File "/Applications/PyCharm 2016.3.app/Contents/helpers/pycharm/_bdd_utils.py", line 91, in run
    number_of_tests = self._get_number_of_tests()
  File "/Applications/PyCharm 2016.3.app/Contents/helpers/pycharm/_bdd_utils.py", line 211, in _get_number_of_tests
    for feature in self._get_features_to_run():
  File "/Applications/PyCharm 2016.3.app/Contents/helpers/pycharm/behave_runner.py", line 231, in _get_features_to_run
    self.__real_runner.run()
  File "/Users/dave/data/projects/api/code/virtualenv/lib/python2.7/site-packages/behave/runner.py", line 672, in run
    return self.run_with_paths()
  File "/Users/dave/data/projects/api/code/virtualenv/lib/python2.7/site-packages/behave/runner.py", line 678, in run_with_paths
    self.load_step_definitions()
  File "/Users/dave/data/projects/api/code/virtualenv/lib/python2.7/site-packages/behave/runner.py", line 658, in load_step_definitions
    exec_file(os.path.join(path, name), step_module_globals)
  File "/Users/dave/data/projects/api/code/virtualenv/lib/python2.7/site-packages/behave/runner.py", line 304, in exec_file
    exec(code, globals, locals)
  File "code/features/steps/common.py", line 5, in <module>
    from django.contrib.auth.models import User
  File "/Users/dave/data/projects/api/code/virtualenv/lib/python2.7/site-packages/django/contrib/auth/models.py", line 4, in <module>
    from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
  File "/Users/dave/data/projects/api/code/virtualenv/lib/python2.7/site-packages/django/contrib/auth/base_user.py", line 52, in <module>
    class AbstractBaseUser(models.Model):
  File "/Users/dave/data/projects/api/code/virtualenv/lib/python2.7/site-packages/django/contrib/auth/base_user.py", line 53, in AbstractBaseUser
    password = models.CharField(_('password'), max_length=128)
  File "/Users/dave/data/projects/api/code/virtualenv/lib/python2.7/site-packages/django/db/models/fields/__init__.py", line 1043, in __init__
    super(CharField, self).__init__(*args, **kwargs)
  File "/Users/dave/data/projects/api/code/virtualenv/lib/python2.7/site-packages/django/db/models/fields/__init__.py", line 166, in __init__
    self.db_tablespace = db_tablespace or settings.DEFAULT_INDEX_TABLESPACE
  File "/Users/dave/data/projects/api/code/virtualenv/lib/python2.7/site-packages/django/conf/__init__.py", line 53, in __getattr__
    self._setup(name)
  File "/Users/dave/data/projects/api/code/virtualenv/lib/python2.7/site-packages/django/conf/__init__.py", line 39, in _setup
    % (desc, ENVIRONMENT_VARIABLE))
django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.

Process finished with exit code 1

How can I run my behave features in the intended way in PyCharm?

Things I tried that didn't work

Setting the run configuration's working directory to .../api/code didn't make a difference.

The suggestion in the stack trace above seems bogus, because the settings file is the default, and I didn't need to set DJANGO_SETTINGS_MODULE to make anything else work in or out of PyCharm, but if I add DJANGO_SETTINGS_MODULE=api.settings to the behave run configuration in PyCharm I get

[some duplicate stack frames removed]
  File "code/features/steps/common.py", line 5, in <module>
    from django.contrib.auth.models import User
  File "/Users/dave/data/projects/api/code/virtualenv/lib/python2.7/site-packages/django/contrib/auth/models.py", line 4, in <module>
    from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
  File "/Users/dave/data/projects/api/code/virtualenv/lib/python2.7/site-packages/django/contrib/auth/base_user.py", line 52, in <module>
    class AbstractBaseUser(models.Model):
  File "/Users/dave/data/projects/api/code/virtualenv/lib/python2.7/site-packages/django/db/models/base.py", line 105, in __new__
    app_config = apps.get_containing_app_config(module)
  File "/Users/dave/data/projects/api/code/virtualenv/lib/python2.7/site-packages/django/apps/registry.py", line 237, in get_containing_app_config
    self.check_apps_ready()
  File "/Users/dave/data/projects/api/code/virtualenv/lib/python2.7/site-packages/django/apps/registry.py", line 124, in check_apps_ready
    raise AppRegistryNotReady("Apps aren't loaded yet.")
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.

When I run django.setup() in features/environment.py (not in before_all, but at the top level) I get farther, but

  • the tests run in my regular database, not in a temporary test database, and
  • behave-django features like context.base_url are not available, so some tests fail.

How can I make this work?

1

There are 1 answers

2
Peterino On BEST ANSWER

(Disclosure: I'm one of the maintainers of behave-django, the integration of behave and Django.)

Behave Is a Standalone Tool

The actual problem is that behave is not meant to be aware of Django and integrate into it. It's meant to run as an external tool. And that's what PyCharm (2016.3.1) seems to take for granted, and what happens when PyCharm runs the tests. The tests are run just as if you ran behave (not python manage.py behave!) from the terminal.

In code/features/steps/common.py, line 5, you have an import towards Django (User model), which requires Django being already running, e.g. via a management command (runserver). In behave-django we require a management command to be run instead, so that a LiveServerTestCase can launch before your code is reached. Django will be ready, because we make it launch a runserver before it hits your code.

JetBrains would have to take this into account if behave-django should work out of the box.

Alternative Integration (Partial Solution)

You can integrate into Django with behave only, no need for behave-django, with a few extra lines of code in environment.py. You will lose a few features of our integration, and you'll have to replicate this integration approach over all your projects, though.

See the Manual Integration section of the behave docs. You could try to replicate behave-django's behavior by adding some of its code to access the live_server_url to your test setup.

The rest is probably up to JetBrains. Sorry for the bad news!