簡體   English   中英

AttributeError:無法設置屬性

[英]AttributeError: can't set attribute

我正在做一個傳統的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來測試視圖,而是創建了一個模擬請求並將其傳遞給view為(調用視圖)在以下測試中

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'}))

這個答案沒有解決這個問題的細節,但是解釋了潛在的問題。 當您嘗試更改的屬性實際上是沒有setter的屬性時,將引發此特定異常“ AttributeError:無法設置屬性”(請參見source )。 如果您可以訪問庫的代碼,則添加一個setter可以解決問題。

編輯:將源鏈接更新為代碼中的新位置。

看來您沒有在Response類中使用self.template 嘗試這樣:

class Response(HttpResponse):
    def __init__(self, template='', calling_context='' status=None):
        HttpResponse.__init__(self, get_template(template).render(calling_context), status)

我看了一下django源代碼,我不知道templatetemplates屬性來自HttpResponse 但是我可以建議您更改測試方法並遷移到模擬框架。 您可以像這樣重寫測試:

@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詳細信息。 也許您需要使用spec屬性,因為django進行了一些類型檢查...但是嘗試使用和不使用它(我不是django專家)。 探索mock框架:它將為您提供許多強大的工具來進行簡單的測試。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM