我正在开发一个遗留的django项目,在那里有一个类定义如下;
from django.http import HttpResponse
class Response(HttpResponse):
def __init__(self, template='', calling_context='' status=None):
self.template = template
self.calling_context = calling_context
HttpResponse.__init__(self, get_template(template).render(calling_context), status)
这个类在视图中使用如下
def some_view(request):
#do some stuff
return Response('some_template.html', RequestContext(request, {'some keys': 'some values'}))
这个类主要是为了让他们可以在单元测试中使用它来执行断言。他们没有使用django.test.Client来测试视图,而是创建了一个模拟请求并将其传递给视图(在测试中将视图称为可调用的,如下所示
def test_for_some_view(self):
mock_request = create_a_mock_request()
#call the view, as a function
response = some_view(mock_request) #returns an instance of the response class above
self.assertEquals('some_template.html', response.template)
self.assertEquals({}, response.context)
问题在于测试套件的一半(相当大的测试套件),一些测试在执行
时开始爆炸return Response('some_template.html', RequestContext(request, {'some keys': 'some values'}))
并且堆栈跟踪是
self.template = template
AttributeError: can't set attribute
完整的堆栈跟踪看起来像
======================================================================
ERROR: test_should_list_all_users_for_that_specific_sales_office
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/austiine/Projects/mped/console/metrics/tests/unit/views/sales_office_views_test.py", line 106, in test_should_list_all_users_for_that_specific_sales_office
response = show(request, sales_office_id=sales_office.id)
File "/Users/austiine/Projects/mped/console/metrics/views/sales_office_views.py", line 63, in show
"sales_office_users": sales_office_users}))
File "/Users/austiine/Projects/mped/console/metrics/utils/response.py", line 9, in __init__
self.template = template
AttributeError: can't set attribute
实际的失败测试是
def test_should_list_all_users_for_that_specific_sales_office(self):
user_company = CompanyFactory.create()
request = self.mock_request(user_company)
#some other stuff
#calling the view
response = show(request, sales_office_id=sales_office.id)
self.assertIn(user, response.calling_context["sales_office_users"])
self.assertNotIn(user2, response.calling_context["sales_office_users"])
节目视图的代码
def show(request, sales_office_id):
user = request.user
sales_office = []
sales_office_users = []
associated_market_names = []
try:
sales_office = SalesOffice.objects.get(id=sales_office_id)
sales_office_users = User.objects.filter(userprofile__sales_office=sales_office)
associated_market_names = Market.objects.filter(id__in= (sales_office.associated_markets.all())).values_list("name", flat=True)
if user.groups.all()[0].name == UserProfile.COMPANY_AO:
associated_market_names = [market.name for market in sales_office.get_sales_office_user_specific_markets(user)]
except:
pass
return Response("sales_office/show.html", RequestContext(request, {'keys': 'values'}))
答案 0 :(得分:34)
这个答案并没有解决这个问题的具体细节,而是解释了潜在的问题。 当您尝试更改的属性实际上是没有设置者的source时,会引发此特定异常“AttributeError:无法设置属性”(请参阅property)。如果您可以访问库的代码,添加setter可以解决问题。
编辑:更新了代码中新位置的源链接。
答案 1 :(得分:0)
您似乎不在self.template
课程中使用Response
。试试这样:
class Response(HttpResponse):
def __init__(self, template='', calling_context='' status=None):
HttpResponse.__init__(self, get_template(template).render(calling_context), status)
答案 2 :(得分:0)
我看了一下django源代码我不知道template
或templates
属性来自HttpResponse
。但我可以建议您更改测试方法并迁移到mock框架。你可以改写你的测试:
@patch("qualified_path_of_response_module.response.Response", spec=Response)
def test_should_list_all_users_for_that_specific_sales_office(self,mock_resp):
user_company = CompanyFactory.create()
request = self.mock_request(user_company)
#some other stuff
#calling the view
response = show(request, sales_office_id=sales_office.id)
self.assertTrue(mock_resp.called)
context = mock_resp.call_args[0][2]
self.assertIn(user, context["sales_office_users"])
self.assertNotIn(user2, context["sales_office_users"])
@patch
装饰器将Response()
类替换为MagicMock()
,并将其作为mock_resp
变量传递给您的测试方法。您还可以使用patch
作为with
构造的上下文管理器,但装饰器是更简洁的方法。我不知道Response
是否只是用于测试的存根类,但在这种情况下,您可以直接修补HttpResponce
,但这取决于您的代码。
您可以找到有关call_args
here的详细信息。也许你需要使用spec
属性,因为django进行了一些类型检查......但尝试使用和不使用它(我不是django专家)。探索mock
框架:它将为您提供许多强大的工具来进行简单的测试。