Django csrf令牌正在修改预期的输出并导致单元测试失败

时间:2019-02-14 18:47:29

标签: python django selenium

我目前正在使用Python进行Harry Percival的“测试驱动开发”,并且在将{%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?

2 个答案:

答案 0 :(得分:0)

与Django紧密结合的好书!错误的根源取决于csrf_token标记的功能,有关其工作原理的文档可以here找到。简而言之,每个会话都有自己的csrf令牌,以确保请求来自您的网页本身,而不仅仅是从其他地方发布到您的服务器。考虑到这一点,对页面的请求和呈现为字符串的模板应该应当具有不同的内容。

您会在书中看到很多观点,问自己是什么测试测试?对于这种情况,似乎您想检查渲染的模板是否为您期望的模板,并且为此,您可能想对reponse.templates而不是response.content.decode进行断言。

如果您遵循该建议,它将最终看起来像这样:

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

答案 1 :(得分:0)

解决方案是模拟令牌生成函数,以便在您需要比较输出是否相等时它具有可预测的值。

例如,下面的代码块将确保 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')
    print('response: ', response.content.decode())
    print('expected: ', expected_html)
    self.assertEqual(response.content.decode(), expected_html)