Testing Reusable Django Apps with Pytest

But if you want to be a code contributor to a dependency such as a reusable Django app (or if you are writing one), the usual pattern is to:

git clone that app to another directory, outside of your project

From within your project dir, usepip install -e /path/to/the/clone

This creates a foo.pth link and/or a foo.egg-link in your project’s virtualenv, rather than copying the code into the project itself, so you can work on the separate repo and have changes reflected in your project in real time.

That’s all well and good, but if you use pytest and need to run tests in the dependency, just running pytest from your project dir won’t find tests that live in the dependency. So can’t you just run pytest from within the dependency’s directory? Not quite – since it’s a Django app, it’s going to assume access to Django itself, and likely to other apps installed in the Django project, such as users. It would be redundant and cumbersome to install Django in the dependency’s directory, and that still wouldn’t solve the problem of access to users etc.

I can’t seem to find mention anywhere of a “best-practice” solution to this dilemma, but after much futzing around and feeling like I must be missing something obvious I tried what should have been plain from the outset:

From the project dir, pip uninstall myapp

From the project dir, create a symlink:ln -s /path/to/the/clone myapp

Add myapp to your .gitignore

Now the separate reusable app appears to Django and to pytest like it’s present in the project, while maintaining physical separation between the project and the dependency. Tests run, and there’s no confusion. Just be sure to .gitignore the symlink.

There’s a gotcha to look out for here: Typically, a reusable app called “myapp” will live in a parent folder that’s also called “myapp”. If you make your symlink to the top-level folder, the imports inside it will not work. You’ll want to create your symlink to the inner folder, e.g.:

ln -s /Users/yourname/dev/myapp/myapp .

Unless I’m mistaken about something, a simple symlink (rather than pip install -e appears to be the easiest way to organize the relationship.