I ended up overriding the management command.
app-name\management\commands\runserver.py:
from __future__ import print_function
import subprocess
from threading import Thread
from django.core.management.commands.runserver import Command as BaseCommand
# or: from devserver.management.commands.runserver import Command as BaseCommand
from django.conf import settings
from termcolor import colored
BEEP_CHARACTER = '\a'
def call_then_log():
try:
output = subprocess.check_output('manage.py test --failfast',
stderr=subprocess.STDOUT, shell=True)
except subprocess.CalledProcessError as ex:
print(colored(ex.output, 'red', attrs=['bold']))
print(BEEP_CHARACTER, end='')
return
print(output)
def run_background_tests():
print('Running tests...')
thread = Thread(target=call_then_log, name='runserver-background-tests')
thread.daemon = True
thread.start()
class Command(BaseCommand):
def inner_run(self, *args, **options):
if settings.DEBUG and not settings.TESTING:
run_background_tests()
super(Command, self).inner_run(*args, **options)
requirements.txt:
termcolor
This runs your tests in a background thread, which runs each time Django auto-reloads. The old thread will be stopped. If any test fails, it will beep and the first failure result will be printed in red to the terminal.
This answer is also worth reading for speeding up your tests for an even faster feedback loop.
test --pattern="*_test.py"this way I just have to name all my test files *_test.py