2017-03-20 1 views
-1

Ich habe einen Test (django pytest), der Objekte in DB manipulieren muss. Die Sache ist, dass nach dem Test die DB "schmutzig" ist und andere Tests fehlschlagen. Ich habe etwas über TransactionTestCase gesehen, aber ich kann nicht verstehen, wie es mit dem Django-Test funktioniert.Django pytest: Lösche DB nach dem Ausführen eines Testfalls

Hier ist ein einfaches Beispiel für meine aktuellen Code:

@pytest.mark.django_db 
def test_something(mock_my_obj): 
    mock_my_obj.save() 
    # test test test 
    ... 
    # I don't want to delete the obj here... 

UPDATE: Zweiter Versuch: Ich habe gelesen, dass TestCase Transaktionen verwenden sollten, und rollen sie für jeden Test zurück. Nichts für mich arbeiten:

from django.test import TestCase 

class MyTests(TestCase): 
    def test_yair_a(self): 
     print 'AAAAAAA' 
     print Account.objects.all() 
     Account.objects.create(account_id=1,account_name='1') 
     print Account.objects.all() 

    def test_yair_b(self): 
     print 'BBBBBBBB' 
     print Account.objects.all() 
     Account.objects.create(account_id=2,account_name='2') 
     print Account.objects.all() 

Ergebnis (die interessanten Teile):

> py.test -s -v -k test_yair 
AAAAAAA 
[] 
[<Account: 1>] 
PASSED 

BBBBBBBB 
[<Account: 1>] 
[<Account: 1>, <Account: 2>] 
PASSED 

keine Transaktion Bedeutung wurde wieder am Ende des Test_a gerollt.

+1

Das ist eigenartig. [Die Dokumente] (http://pytest-django.readthedocs.io/en/latest/database.html#enabling-database-access-in-tests) geben an, dass Testtransaktionen nach jedem Test zurückgesetzt werden. Vielleicht hat es damit zu tun, dass Sie das Objekt injizieren, anstatt es in der Testfunktion selbst zu erstellen. –

+0

Ich glaube nicht - der Schein ist nur ein Objekt. Ich speichere es im Test selbst an die DB – reformy

+0

Kannst du ein [minimal funktionierendes Beispiel] (https://stackoverflow.com/help/mcve) posten? –

Antwort

0

Das Problem war, dass Django standardmäßig eine Transaktion auf der Standard-DB erstellt. Ich brauche eine Transaktion in einer anderen DB. Dies ist meine Einstellungsdatei:

ROOT_PASS = 'ohnoyoudidnt' 
ROOT_USER = 'root' 
ROOT_HOST = 'localhost' 

DATABASES = { 
    'default': { 
     'ENGINE': 'django.db.backends.mysql', 
     'NAME': 'default_db', 
     'USER': ROOT_USER, 
     'PASSWORD': ROOT_PASS, 
     'HOST': ROOT_HOST, 
     'PORT': '3306', 
    }, 
    'my_app': { 
     'ENGINE': 'django.db.backends.mysql', 
     'NAME': 'my_app_db', 
     'USER': ROOT_USER, 
     'PASSWORD': ROOT_PASS, 
     'HOST': ROOT_HOST, 
     'PORT': '3306' 
    }, 

Um dies zu lösen, muss man den transaction.atomic(using='my_app') Block, verwenden und einen Fehler bei dem es um Rollback werfen. Natürlich wollte ich dafür einen Decorator schreiben, aber mit pytest zu arbeiten war nicht so einfach wie ich zuerst dachte, da pytest selbst die Methode vor meinem Code manipuliert (bei Verwendung von Mocks und Patches).

Nach ein paar Stunden habe ich diesen Dekorateur, der funktioniert!

from decorator import decorator 
import pytest 
from django.db import transaction 


class TestTempException(Exception): 
    pass 


def testing_w_transaction(using): 
    def testing_w_transaction_inner(function): 
     def func_wrapper(f, *args, **kwargs): 
      try: 
       with transaction.atomic(using=using): 
        f(*args, **kwargs) 
        raise TestTempException() 
      except TestTempException: 
       pass 
     return decorator(func_wrapper, pytest.mark.django_db(function)) 
    return testing_w_transaction_inner 

Verbrauch:

@testing_w_transaction(using='my_app') 
def test_my_method(mock_object, ...): 
    # test test test 
Verwandte Themen