Mes Django tests unitaires prennent beaucoup de temps à exécuter, donc je cherche des moyens d'accélérer cela. J'envisage d'installer un SSD , mais je sais que cela a aussi ses inconvénients. Bien sûr, il y a des choses que je pourrais faire avec mon code, mais je cherche un correctif structurel. Même l'exécution d'un seul test est lente car la base de données a besoin pour être reconstruit/sud migré à chaque fois. Voici donc mon idée ...
Étant donné que je sais que la base de données de test sera toujours assez petite, pourquoi ne puis-je pas simplement configurer le système pour toujours conserver la base de données de test entière dans la RAM? Ne touchez jamais du tout le disque. Comment configurer cela dans Django? Je préférerais continuer à utiliser MySQL puisque c'est ce que j'utilise en production, mais si SQLite 3 ou autre chose rend cela facile, j'irais dans ce sens.
SQLite ou MySQL ont-ils une option pour s'exécuter entièrement en mémoire? Il devrait être possible de configurer un disque RAM puis de configurer la base de données de test pour y stocker ses données, mais je ne sais pas comment dire Django/MySQL pour utiliser un répertoire de données différent pour une certaine base de données, d'autant plus qu'il continue d'être effacé et recréé à chaque exécution (je suis sur un Mac FWIW).
Si vous définissez votre moteur de base de données sur sqlite3 lorsque vous exécutez vos tests, Django utilisera une base de données en mémoire .
J'utilise du code comme celui-ci dans mon settings.py
pour définir le moteur sur sqlite lors de l'exécution de mes tests:
if 'test' in sys.argv:
DATABASE_ENGINE = 'sqlite3'
Ou en Django 1.2:
if 'test' in sys.argv:
DATABASES['default'] = {'ENGINE': 'sqlite3'}
Et enfin dans Django 1.3 et 1.4:
if 'test' in sys.argv:
DATABASES['default'] = {'ENGINE': 'Django.db.backends.sqlite3'}
(Le chemin complet vers le backend n'est pas strictement nécessaire avec Django 1.3, mais rend le paramètre forward compatible.)
Vous pouvez également ajouter la ligne suivante, au cas où vous auriez des problèmes avec les migrations Sud:
SOUTH_TESTS_MIGRATE = False
Je crée généralement un fichier de paramètres séparé pour les tests et je l'utilise dans la commande de test, par exemple.
python manage.py test --settings=mysite.test_settings myapp
Il présente deux avantages:
Vous n'avez pas besoin de rechercher test
ou un tel mot magique dans sys.argv, test_settings.py
peut simplement être
from settings import *
# make tests faster
SOUTH_TESTS_MIGRATE = False
DATABASES['default'] = {'ENGINE': 'Django.db.backends.sqlite3'}
Ou vous pouvez l'ajuster davantage pour vos besoins, séparant proprement les paramètres de test des paramètres de production.
Un autre avantage est que vous pouvez exécuter le test avec le moteur de base de données de production au lieu de sqlite3 en évitant les bogues subtils, donc lors du développement de l'utilisation
python manage.py test --settings=mysite.test_settings myapp
et avant de valider le code, exécutez une fois
python manage.py test myapp
juste pour être sûr que tous les tests passent vraiment.
MySQL prend en charge un moteur de stockage appelé "MEMORY", que vous pouvez configurer dans votre configuration de base de données (settings.py
) En tant que tel:
'USER': 'root', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'OPTIONS': {
"init_command": "SET storage_engine=MEMORY",
}
Notez que le moteur de stockage MEMORY ne prend pas en charge les colonnes blob/texte, donc si vous utilisez Django.db.models.TextField
cela ne fonctionnera pas pour vous.
Je ne peux pas répondre à votre question principale, mais il y a deux ou trois choses que vous pouvez faire pour accélérer les choses.
Tout d'abord, assurez-vous que votre base de données MySQL est configurée pour utiliser InnoDB. Ensuite, il peut utiliser des transactions pour restaurer l'état de la base de données avant chaque test, ce qui, selon mon expérience, a entraîné une accélération massive. Vous pouvez passer une commande init de base de données dans votre settings.py (syntaxe Django 1.2):
DATABASES = {
'default': {
'ENGINE':'Django.db.backends.mysql',
'Host':'localhost',
'NAME':'mydb',
'USER':'whoever',
'PASSWORD':'whatever',
'OPTIONS':{"init_command": "SET storage_engine=INNODB" }
}
}
Deuxièmement, vous n'avez pas besoin d'exécuter les migrations Sud à chaque fois. Ensemble SOUTH_TESTS_MIGRATE = False
dans votre settings.py et la base de données sera créée avec plain syncdb, ce qui sera beaucoup plus rapide que l'exécution de toutes les migrations historiques.
Vous pouvez faire un double réglage:
J'utilise les deux astuces et je suis assez content.
Comment le configurer pour MySQL sur Ubuntu:
$ Sudo service mysql stop
$ Sudo cp -pRL /var/lib/mysql /dev/shm/mysql
$ vim /etc/mysql/my.cnf
# datadir = /dev/shm/mysql
$ Sudo service mysql start
Attention, c'est juste pour les tests, après le redémarrage de votre base de données de la mémoire est perdue!
Une autre approche: avoir une autre instance de MySQL fonctionnant dans un tempfs qui utilise un RAM Disk. Instructions dans ce billet de blog: Accélérer MySQL pour test dans Django .
Avantages:
En étendant la réponse d'Anurag, j'ai simplifié le processus en créant les mêmes paramètres test_settings et en ajoutant les éléments suivants à manage.py
if len(sys.argv) > 1 and sys.argv[1] == "test":
os.environ.setdefault("Django_SETTINGS_MODULE", "mysite.test_settings")
else:
os.environ.setdefault("Django_SETTINGS_MODULE", "mysite.settings")
semble plus propre car sys est déjà importé et manage.py n'est utilisé que via la ligne de commande, donc pas besoin d'encombrer les paramètres