2016-08-04 50 views
0

ich zur Zeit einen Komponententest für die folgende get_can_edit Funktion in meinem Serializer schreibt:Django REST-Framework - Unit Test Fehler

def get_can_edit(self, obj): 
    request = self.context.get('request') 
    user = User.objects.get(username=request.user) 
    return user == obj.admin 

In meinem Test, rufe ich die Funktion hier:

def test_get_can_edit(self): 
    self.request1 = RequestFactory().post('./fake_path') 
    self.request1.user = SimpleLazyObject(self.user1) 
    self.request1.query_params = {} 
    self.serializer1 = ConferenceSerializer(context={'request': self.request1}) 
    self.canEdit1 = self.serializer1.get_can_edit(self.conference) 

Wenn ich den Test durchführe, schlägt er den Fehler fehl: 'User' object is not callable, und verweist auf die folgende Zeile im Serializer get_can_edit Funktion:

user = User.objects.get(username=request.user) 

Wenn Sie jedoch im Browser ausgeführt wird, funktioniert die Funktion get_can_edit ordnungsgemäß und hat kein Problem damit, dass das Objekt 'User' aufrufbar ist.

Ich nahm ursprünglich an, dass es ein Problem mit dem Format der gefälschten Daten gab, die ich schuf (ich verwende factory_boy und RequestFactory, um die gefälschten Daten zu verursachen). Mit einem Debugger ging ich in die Funktion get_can_edit, indem ich den Test aufruft, und über den Server, indem ich eine echte Anfrage machte. In beiden Fällen waren request.user und obj.admin in der korrekten Form, so dass ich einen Datenformatierungsfehler ausschloss.

Als nächstes habe ich versucht,

User.objects.get(username=request.user) 

in dem Debugger. Es funktionierte für die echte Anforderung auf dem Server und gab denselben 'User' object is not callable Fehler für die falsche Anforderung in dem Test zurück. Ich habe einen schnellen Stack-Überlauf/Google-Suche nach object is not callable Fehlern in Django gemacht, aber es sah so aus, als ob andere Fälle gelöst wurden, indem sichergestellt wurde, dass ein Modell korrekt importiert wurde (meins wird definitiv korrekt importiert).

Also an diesem Punkt weiß ich, dass es ein Problem mit meinem Testfall gibt, der nicht mit der echten Anfrage existiert, aber ich kann nicht wirklich herausfinden, was es ist, und mir sind die Ideen ausgegangen.

Voll Code:

The serializer

The test

Vielen Dank, lassen Sie mich wissen, ob es einen einfacheren Weg, um dies zu realisieren.



UPDATE: Also ging ich zurück in den zwei verschiedenen Debugger und tat User.objects.all(). Der Server im Server mit der echten Anfrage hat die korrekte Benutzerliste zurückgegeben. Derjenige im Test mit der gefälschten Anfrage hat gerade anonymoususer zurückgegeben. Da ich factory_boy verwende, um meine gefälschten Benutzer zu erstellen, kann django es in User.objects nicht finden.

Mir wurde gesagt, dass ich in meinen Komponententests keine echten Anfragen stellen soll, so dass es nicht möglich ist, einen tatsächlichen Benutzer zu erstellen.

Ich versuchte auch, die get_can_edit Funktion zu ändern, um User.objects. nicht zu überprüfen. request.user ist ein SimpleLazyObject, der den Benutzer enthält.Was ich versuchte, war request.user.id und Vergleich mit obj.admin.id, aber anscheinend, wenn Sie so ziemlich alles zu einem SimpleLazyObject tun, konsultiert es User.objects, um zum tatsächlichen Benutzer zu kommen, der damit verbunden ist, also hatte es noch den gleichen Fehler 'User' object is not callable.

Unterm Strich also ist dies: ich ohne einen gefälschten Benutzer User.objects hinzufügen muß einem echten antrag

+1

Sie verwenden 'app.models.User' und' django.contrib.auth.model.User'. Was ist der Grund dafür? Können Sie auch die relevanten Modelle posten? –

+0

Sie sind das gleiche Modell ... Ich bin mir nicht sicher, warum sie anders importiert werden (ich bin nicht der einzige Kollaborateur auf diesen Seiten), aber ich habe gerade versucht, die Art und Weise zu ändern, in der sie importiert werden gleiches Problem. Dokumentation zum Benutzermodell finden Sie hier: https://docs.djangoproject.com/de/1.9/topics/auth/default/ – Tom

Antwort

1

Es wurde hier gelöst: Django REST Framework - Fake objects for unit tests

Grundsätzlich factory_boy Fabriken benötigt unterschiedlich eingerichtet werden. Wo ich meine Fabriken I definiert die folgende Zeile hatte:

class UserFactory(factory.Factory): 

Aber anscheinend statt factory.Factory, sollte sie factory.DjangoModelFactory sagen, wie so:

class UserFactory(factory.DjangoModelFactory): 

Dies ist ein wenig anstößig war, da die factory_boydocumentation hat ein Beispiel auf der ersten Seite mit factory.Factory, aber später sagt Ihnen, DjangoModelFactory zu verwenden. Ich denke, das ist es, was ich verdiene, weil ich die Dokumentation nicht gründlich gelesen habe.

2

Es ist besser, eine Basisklasse zu schaffen, um sie über alle Tests zu verwenden. Diese Klasse erstreckt sich auch von der APIClient DRF-Klasse, die HTTP-Methoden unterstützt, und Sie müssen Request Objekte nicht manuell erstellen.

from rest_framework.test import APITestCase 

class BaseAPITestCase(APITestCase): 
    """ 
    Base class to initialize the test cases 
    """ 

    self.user = YourUserFactory.create_batch(1) 
    self.user_client = self.get_client(user=self.user) 

in Ihrem Test

class YourTestClass(BaseAPITestCase): 

    def test_get_can_edit(self): 
     response = self.user_client.post('./fake_path') 
     # proccess your response