Django REST框架 - 单元测试错误

时间:2016-08-04 19:43:37

标签: python django unit-testing django-rest-framework

我目前正在为序列化程序中的以下get_can_edit函数编写单元测试:

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

在我的测试中,我在这里调用函数:

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)

当我运行测试时,它失败了错误:'User' object is not callable,并引用了序列化程序get_can_edit函数中的以下行:

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

但是,在浏览器中运行时,get_can_edit函数可以正常执行,并且“用户”功能没有问题。 objet可以赎回。

我最初认为我正在创建的假数据格式存在问题(我使用factory_boyRequestFactory来创建虚假数据)。使用调试器,我通过调用测试进入get_can_edit函数,并通过发出实际请求通过服务器。在这两种情况下,request.userobj.admin的格式都是正确的,因此我排除了数据格式错误。

接下来,我试过

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

在调试器中。它适用于服务器中的实际请求,并在测试中为假请求返回了相同的'User' object is not callable错误。我在Django中对object is not callable错误进行了快速堆栈溢出/谷歌搜索,但看起来其他案例都是通过确保正确导入模型来解决的(我的版本肯定是正确导入的)。

所以在这一点上我知道我的测试用例存在问题,而实际请求并不存在,但我无法弄清楚它是什么,我正在运行没有想法。

完整代码:

The serializer

The test

非常感谢,如果有更简单的方法,请告诉我。



更新:  所以我回到了两个不同的调试器并做了User.objects.all()。服务器中具有实际请求的那个返回了正确的用户列表。测试中的虚假请求刚刚返回匿名用户。因为我使用factory_boy创建我的假用户,所以django无法在User.objects中找到它。

我被告知不要在我的单元测试中提出真正的请求,因此创建一个真正的用户是不可能的。

我还尝试将get_can_edit功能更改为不检查User.objects.request.user是包含用户的SimpleLazyObject。我尝试做的是request.user.id并将其与obj.admin.id进行比较,但显然当你对SimpleLazyObject执行任何操作时,它会咨询User.objects以获取与实际用户关联的内容有了它,所以它仍然有同样的错误'User' object is not callable

所以最重要的是:我需要在User.objects添加虚假用户而不提出真实请求

2 个答案:

答案 0 :(得分:2)

创建基类以便在所有测试中使用它更好。此类也从APIClient DRF类扩展,它支持HTTP方法,您不需要手动创建Request个对象。

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)

在你的测试中

class YourTestClass(BaseAPITestCase):

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

答案 1 :(得分:1)

这里解决了:Django REST Framework - Fake objects for unit tests

基本上factory_boy工厂需要以不同的方式设置。在我定义工厂的地方,我有以下几行:

class UserFactory(factory.Factory):

但显然不是factory.Factory,而是应该factory.DjangoModelFactory这样说:

class UserFactory(factory.DjangoModelFactory):

这有点令人讨厌,因为factory_boy documentation在第一页上有factory.Factory的示例,但稍后会告诉您使用DjangoModelFactory。我想这是我没有彻底阅读文档所应得的。