2016-04-04 9 views
1

Ich bin auf Django 1.8 (mit pytest), und ich habe die folgende Konfiguration:Wie können Datenbankeinstellungen in Django-Tests überschrieben werden?

  • A default und eine readonly Datenbank von einem MasterSlaveRouter verwaltet, die DB auf eine Verbindung oder die andere je nach leitet Anrufe ob sie‘ Lese- oder Schreiboperationen.
  • In meiner Entwicklungsumgebung haben beide Einträge im settings.DATABASES Wörterbuch die gleiche Konfiguration (sie verwenden nur eine andere Verbindung, aber die Datenbank ist die gleiche). In meiner Testumgebung gibt es nur eine default Datenbank.
  • Ich habe ein post_save Signal ausgelöst, wenn ein Modell Foo gespeichert wird.
  • Ich habe eine atomare Operation (mit @transaction.atomic dekoriert), die eine Foo Instanz ändert und .save() darauf zweimal aufruft. Da kein benutzerdefinierter Parameter using an den Decorator übergeben wird, ist die Transaktion nur in der Datenbank default aktiv.

Der post_save Rückruf erstellt einen Bar Datensatz mit einem OneToOneField zeigt auf Foo, aber erst nach Überprüfung, ob ein Bar Datensatz mit diesem foo_id existiert bereits (in der Reihenfolge IntegrityError zu vermeiden). Diese Prüfung wird durch Ausführen dieser Abfrage getan:

already_exists = Bar.filter(foo=instance).exists() 

Diese Ordnung ist das erste Mal, der post_save Rückruf aufgerufen wird. Ein Bar Datensatz wird erstellt und alles funktioniert einwandfrei. Das zweite Mal, obwohl eine solche Bar Instanz gerade in der vorherigen Foo Speichern erstellt wurde, da Filterung eine Leseoperation ist, wird es unter Verwendung der readonly Verbindung durchgeführt, und daher endet already_exists enthält den Wert False und die Erstellung von a Es wird ein neuer Datensatz ausgelöst, der schließlich einen IntegrityError auslöst, da bei der Ausführung der Erstellungsoperation auf der default-Verbindung bereits ein Datensatz mit dieser vorhanden ist.

Ich habe versucht, das DATABASES Wörterbuch von dev_settings zu test_settings zu kopieren, aber das hat viele Tests abgebrochen. Ich las dann über die override_settings Dekorateurin und dachte, es wäre perfekt für meine Situation. Zu meiner Überraschung hat es jedoch nicht funktioniert. Es scheint, dass an einem Punkt, wenn die Anwendung initiiert wird, das DATABASES Wörterbuch (das einzige mit default von den test_settings) zwischengespeichert wird und dann, obwohl ich setting.DATABASES ändern, der neue Wert ist einfach nicht mehr zugegriffen.

Wie kann ich die Datenbankkonfiguration für einen bestimmten Test richtig überschreiben?

Antwort

0

Hum ... gut, wenn Sie nur Pytest verwenden, denke ich, dass Sie Ihre Datenbanken nach den Tests aufräumen müssen.

, nun django Einstellungen außer Kraft zu setzen, ist es gut zu:

pytestmark = pytest.mark.django_db 

@pytest.mark.django_db 
def test_foo(): 
    pass 

Wenn Sie Ihre Tests ausführen, können Sie die create-db gesetzt:

from django.test import override_settings 
@override_settings(DATABASE_CONFIG=<new_config>) 
def test_foo(): 
    pass 

Sie die pytest-django versuchen sollten, param, um py zu erzwingen.Test eine neue Datenbank erstellen oder wenn Sie Ihre db wieder verwenden möchten, können Sie die Wiederverwendung-db gesetzt, wie:

$ py.test --create-db 
$ py.test --reuse-db 

Kasse: Oficial docs