run_the_race
run_the_race

Reputation: 2318

Add dir to Django search path for tests

I am using a single django for various custom distributions. I arrived at a solution where the apps unique to each distribution live outside of the django projects folder (lets call it DIR/), and added this outside DIR/ to the Django path using How to keep all my django applications in specific folder (adding to the sys.path solution)

The project runs, however now it does not discover tests. Before moving the apps out of the Django project folder I could simply run all tests with:

manage.py test

However, now the tests aren't found. In addition to adding DIR/ to settings.py, I tried adding it to manage.py and it did not help. By reading the django docs I discovered I can specify a module like this:

manage.py test app_name.tests

The above works, but is impractical for many apps. How can I add a path for where to search for tests?

I read this but it only describes the problem, not the solution: Django test runner not finding tests

Request for my project structure:

somefolder/
  |-- dist/
  |     |-- dist1/apps/
  |     |       |---- app11/
  |     |       '---- app12/
  |     |
  |     '-- dist2/apps/
  |             |---- app21/
  |             '---- app22/
  |-- src/
        |-- manage.py
        |-- project/settings.py
        |-- appA/
        '-- appB/

Since asking have found out this works (not ideal):

manage.py test app11 app12 app21 app22 --keepdb

Upvotes: 5

Views: 2397

Answers (1)

Augusto Destrero
Augusto Destrero

Reputation: 4345

The key is to add some empty __init__py files in your dist, dist/dist1 and dist/dist1/apps directories.

I just tried putting together a toy project with the following structure:

.
├── dist
│   ├── dist1
│   │   ├── apps
│   │   │   ├── app_external
│   │   │   │   ├── admin.py
│   │   │   │   ├── apps.py
│   │   │   │   ├── __init__.py
│   │   │   │   ├── migrations
│   │   │   │   │   └── __init__.py
│   │   │   │   ├── models.py
│   │   │   │   ├── tests.py
│   │   │   │   └── views.py
│   │   │   └── __init__.py
│   │   └── __init__.py
│   └── __init__.py
└── src
    ├── app_internal
    │   ├── admin.py
    │   ├── apps.py
    │   ├── __init__.py
    │   ├── migrations
    │   │   └── __init__.py
    │   ├── models.py
    │   ├── tests.py
    │   └── views.py
    ├── manage.py
    └── project
        ├── __init__.py
        ├── settings.py
        ├── urls.py
        └── wsgi.py

Notice that there is an empty __init__.py file in each directory under dist/. This is what makes each directory a Python package and make the Python test machinery to look for tests inside those directories.

Also notice that I have an internal app called app_internal and an external one called app_external in a directory structure similar to yours.

Both the app_internal and app_external have one fake test in the tests.py file.

app_external/tests.py content:

from django.test import TestCase

class ExternalTestCase(TestCase):

    def test_fake(self):
        self.assertTrue(False)

app_internal/tests.py content:

from django.test import TestCase

class InternalTestCase(TestCase):

    def test_fake(self):
        self.assertTrue(True)

Here we expect that the app_external test will fail and the app_internal test will succeed.

I can call the app_internal test by giving the usual command:

$ ./manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK
Destroying test database for alias 'default'...

And I can call the app_external test by giving the following command:

$ ./manage.py test ..
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
F
======================================================================
FAIL: test_fake (dist.dist1.apps.app_external.tests.ExternalTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/augusto/develop/apps_outside/dist/dist1/apps/app_external/tests.py", line 10, in test_fake
    self.assertTrue(False)
AssertionError: False is not true

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures=1)
Destroying test database for alias 'default'...

Notice how I passed .. as the parameter to the test command.

This point to the parent directory with respect to src/, so it finds the dist package and every other package inside it. I expect that this will find all tests under your dist/ directory.

I can also run all internal and external tests at once by giving the following command:

$ ./manage.py test . ..
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.F
======================================================================
FAIL: test_fake (dist.dist1.apps.app_external.tests.ExternalTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/augusto/develop/apps_outside/dist/dist1/apps/app_external/tests.py", line 10, in test_fake
    self.assertTrue(False)
AssertionError: False is not true

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)
Destroying test database for alias 'default'...

I tested this using Django 1.11.23 and Python 2.7.12.

Upvotes: 8

Related Questions