Web browser automation

You can access the test HTTP server from your preferred web automation library via context.base_url (normally, this would be set to http://localhost:8081). Alternatively, you can use context.get_url(), which is a helper function for absolute paths and reversing URLs in your Django project. It takes an absolute path, a view name, or a model as an argument, similar to django.shortcuts.redirect.


# Using Splinter
@when(u'I visit "{url}"')
def visit(context, url):
    context.browser.visit(context.base_url + url)
# Get context.base_url
# Get context.base_url + '/absolute/url/here'
# Get context.base_url + reverse('view-name')
# Get context.base_url + reverse('view-name', 'with args', and='kwargs')
context.get_url('view-name', 'with args', and='kwargs')
# Get context.base_url + model_instance.get_absolute_url()

Django’s testing client

Internally, Django’s TestCase is used to maintain the test environment. You can access the TestCase instance via context.test.

# Using Django's testing client
@when(u'I visit "{url}"')
def visit(context, url):
    # save response in context for next step
    context.response = context.test.client.get(url)

Simple testing

If you only use Django’s testing client then behave tests can run much quicker with the --simple command line option. In this case transaction rollback is used for test automation instead of flushing the database after each scenario, just like in Django’s standard TestCase.

No HTTP server is started during the simple testing, so you can’t use web browser automation. Accessing context.base_url or calling context.get_url() will raise an exception.

unittest + Django assert library

Additionally, you can utilize unittest and Django’s assert library.

@then(u'I should see "{text}"')
def visit(context, text):
    # compare with response from ``when`` step
    response = context.response
    context.test.assertContains(response, text)

Database transactions per scenario

Each scenario is run inside a database transaction, just like your regular TestCases. So you can do something like:

@given(u'user "{username}" exists')
def create_user(context, username):
    # This won't be here for the next scenario
    User.objects.create_user(username=username, password='correcthorsebatterystaple')

And you don’t have to clean the database yourself.

django_ready hook

You can add a django_ready function in your file in case you want to make per-scenario changes inside a transaction.

For example, if you have factories you want to instantiate on a per-scenario basis, you can initialize them in like this:

from myapp.main.tests.factories import UserFactory, RandomContentFactory

def django_ready(context, scenario):
    # This function is run inside the transaction

Or maybe you want to modify the test instance:

from rest_framework.test import APIClient

def django_ready(context, scenario):
    context.test.client = APIClient()

Fixture loading

behave-django can load your fixtures for you per feature/scenario. There are two approaches to this:

  • loading the fixtures in, or
  • using a decorator on your step function

Fixtures in

In we can load our context with the fixtures array.

def before_scenario(context, scenario):
    context.fixtures = ['user-data.json']

This fixture would then be loaded before every scenario.

If you wanted different fixtures for different scenarios:

def before_scenario(context, scenario):
    if == 'User login with valid credentials':
        context.fixtures = ['user-data.json']
    elif == 'Check out cart':
        context.fixtures = ['user-data.json', 'store.json', 'cart.json']

You could also have fixtures per Feature too

def before_feature(context, feature):
    if == 'Login':
        context.fixtures = ['user-data.json']
        # This works because behave will use the same context for
        # everything below Feature. (Scenarios, Outlines, Backgrounds)

Of course, since context.fixtures is really just a list, you can mutate it however you want, it will only be processed upon leaving the before_scenario() function of your file.


If you provide initial data via Python code using the ORM you need to place these calls in before_scenario() even if the data is meant to be used on the whole feature. This is because Django’s LiveServerTestCase resets the test database after each scenario.

Fixtures using a decorator

You can define Django fixtures using a function decorator. The decorator will load the fixtures in the before_scenario, as documented above. It is merely a convenient way to keep fixtures close to your steps.

from behave_django.decorators import fixtures

@when('someone does something')
def step_impl(context):

Command line options

You can use regular behave command line options with the behave management command.

$ python behave --tags @wip

Additional command line options provided by django_behave:


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.


Starting with Django 1.8, the --keepdb flag was added to test to facilitate faster testing by using the existing database instead of recreating it each time you run the test. This flag enables behave --keepdb to take advantage of that feature. More information about --keepdb.


Use Django’s simple TestCase which rolls back the database transaction 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.

Behave configuration file

You can use behave’s configuration file. Just create a behave.ini, .behaverc, setup.cfg or tox.ini file in your project’s root directory and behave will pick it up. You can read more about it in the behave docs.

For example, if you want to have your features directory somewhere else. In your .behaverc file, you can put


Behave should now look for your features in those folders.