Django csrf标记正在修改预期输出并导致单元测试失败

9avjhtql  于 2022-11-18  发布在  Go
关注(0)|答案(2)|浏览(102)

我目前正在使用Harry Percival的Python测试驱动开发,在将{% csrf_token %}添加到html模板后,我遇到了一个响应问题。
由于这是测试驱动的开发,有几个单元测试失败了。
移除{% csrf_token %}时,测试通过。当它存在于程式码中时,它会修改回应以包含未预期的行

<input type="hidden" name="csrfmiddlewaretoken" value="WaPf57...">

显示在原始行的下方“

<body>
    <h1>Your To-Do List</h1>
        <form method="POST">
            <input name="item_text" id="id_new_item" placeholder="Enter a to-do item" />
            {% csrf_token %}
        </form>
        <table id="id_list_table">
            <tr><td>{{ new_item_text }}</td></tr>
        </table>
</body>

在下面的单元测试中,我已经将实际的和预期的输出到我的控制台,并且我收到了另一行带有csrfmiddleware令牌的代码。

def test_home_page_returns_correct_html(self):
    request = HttpRequest()
    response = home_page(request)
    expected_html = render_to_string('home.html')
    print('response: ', response.content.decode())
    print('expected: ', expected_html)
    self.assertEqual(response.content.decode(), expected_html)

有没有办法从响应中删除它,或者我应该修改测试,使它包括所有预期的HTML,并忽略“隐藏的”csrfmiddlewaretoken?

zf9nrax1

zf9nrax11#

解决方案是模拟令牌生成函数,以便在需要比较输出是否相等时,它具有可预测的值。
例如,下面的代码块将确保html输出包含<input type="hidden" name="csrfmiddlewaretoken" value="predicabletoken">,而不是随机标记字符串。

from unittest import mock

from django.test import TestCase

@mock.patch('django.template.context_processors.get_token', mock.Mock(return_value='predicabletoken'))
class HomeTests(TestCase):
  def test_home_page_returns_correct_html(self):
    request = HttpRequest()
    response = home_page(request)
    expected_html = render_to_string('home.html', request=request)
    print('response: ', response.content.decode())
    print('expected: ', expected_html)
    self.assertEqual(response.content.decode(), expected_html)
rekjcdws

rekjcdws2#

这是一本学习Django的好书!你的错误来源是基于csrf_token标签的功能,关于它如何工作的文档可以在这里找到。简而言之,每个会话都有自己的csrf令牌,以确保请求来自您的网页本身,而不是从其他地方发布到您的服务器。记住这一点,对页面的请求和呈现为字符串的模板应该具有不同内容。
在这本书中你会经常看到的一点是问你自己这个测试测试的是什么?对于这个例子,你似乎想检查呈现的模板是你期望的模板,为此你可能想对response.templates而不是response.content.decode做一个Assert。
如果你按照这个建议去做,它最终会看起来像这样:

self.assertEqual(response.templates[0].name, 'home.html')

相关问题