我正在为我的Django Rest Framework编写一些测试,并试图让它们尽可能简单。之前,我正在使用工厂男孩创建对象,以便保存可用于GET请求的对象。
为什么测试中的POST请求没有在我的测试数据库中创建实际对象?使用实际的API一切正常,但我无法在测试中获得POST以保存对象以使其可用于GET请求。有什么我想念的吗?
from rest_framework import status
from rest_framework.test import APITestCase
# from .factories import InterestFactory
class APITestMixin(object):
"""
mixin to perform the default API Test functionality
"""
api_root = '/v1/'
model_url = ''
data = {}
def get_endpoint(self):
"""
return the API endpoint
"""
url = self.api_root + self.model_url
return url
def test_create_object(self):
"""
create a new object
"""
response = self.client.post(self.get_endpoint(), self.data)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data, self.data)
# this passes the test and the response says the object was created
def test_get_objects(self):
"""
get a list of objects
"""
response = self.client.get(self.get_endpoint())
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data, self.data)
# this test fails and says the response is empty [] with no objects
class InterestTests(APITestCase, APITestMixin):
def setUp(self):
self.model_url = 'interests/'
self.data = {
'id': 1,
'name': 'hiking',
}
# self.interest = InterestFactory.create(name='travel')
"""
if I create the object with factory boy, the object is
there. But I don't want to have to do this - I want to use
the data that was created in the POST request
"""
你可以看到几行注释掉的代码是我需要通过工厂男孩创建的对象,因为对象没有被创建和保存(虽然创建测试确实传递并说出对象已创建。)
我没有发布任何模型,序列化程序或视图集代码,因为实际的API有效,这是测试特有的问题。
答案 0 :(得分:4)
首先,Django TestCase
(APITestCase
的基类)将测试代码包含在数据库事务中,该事务在测试结束时回滚(refer)。这就是为什么test_get_objects
无法看到test_create_object
然后,从(Django Testing Docs)
让测试改变彼此的数据,或者让测试依赖于另一个测试改变数据本身就是脆弱的。
我想到的第一个原因是你不能依赖测试的执行顺序。目前,TestCase中的顺序似乎是按字母顺序排列的。 test_create_object
恰好在test_get_objects
之前被执行了。如果您将方法名称更改为test_z_create_object
,test_get_objects
将首先出现。最好让每个测试独立
针对您的案例的解决方案,如果您仍然希望在每次测试后重置数据库,请使用APISimpleTestCase
更多推荐,小组测试。例如,将test_create_object
,test_get_objects
重命名为subtest_create_object
,subtest_get_objects
。然后创建另一个测试方法以根据需要调用两个测试