python - pytest-django:这是用参数测试 View 的正确方法吗?

标签 python django pytest django-testing pytest-django

假设我正在 Django 应用程序中测试 RSS 提要 View ,我应该这样做吗?

def test_some_view(...):
    ...
    requested_url = reverse("personal_feed", args=[some_profile.auth_token])
    resp = client.get(requested_url, follow=True)
    ...
    assert dummy_object.title in str(resp.content)
  1. reverse 并将其传递给 client.get() 是否是正确的测试方法?我认为它比简单地 .get() URL 更 DRYer 和更面向 future 。

  2. 我是否应该以这种方式断言 dummy_object 在响应中?

  3. 我在这里使用响应对象的 str 表示进行测试。什么时候这样做与使用 selenium 比较好?我知道它可以更轻松地验证所述 obj 或属性(如 dummy_object.title)是否封装在 H1 标记中。另一方面,如果我不关心 obj 的如何表示,那么像上面那样做会更快。

最佳答案

重新评估我的评论(没有仔细阅读问题并忽略了 RSS 提要内容):

  1. Is reverse-ing and then passing that into the client.get() the right way to test? I thought it's DRYer and more future-proof than simply .get()ing the URL.

我同意这一点——从 Django 的角度来看,您正在测试您的 View ,而不关心它们映射到的确切端点。因此,使用 reverse 是 IMO 明确而正确的方法。

  1. Should I assert that dummy_object is in the response this way?

这里要注意。 response.content 是字节串,因此在 str(resp.content) 中断言 dummy_object.title 是危险的。考虑以下示例:

from django.contrib.syndication.views import Feed

class MyFeed(Feed):
    title = 'äöüß'
    ...

urls 中注册 feed:

urlpatterns = [
    path('my-feed/', MyFeed(), name='my-feed'),
]

测试:

@pytest.mark.django_db
def test_feed_failing(client):
    uri = reverse('news-feed')
    resp = client.get(uri)
    assert 'äöüß' in str(resp.content)


@pytest.mark.django_db
def test_feed_passing(client):
    uri = reverse('news-feed')
    resp = client.get(uri)
    content = resp.content.decode(resp.charset)
    assert 'äöüß' in content

一个会失败,另一个不会因为正确的编码处理。

至于检查本身,我个人总是更喜欢将内容解析为一些有意义的数据结构,而不是使用原始字符串,即使是对于简单的测试也是如此。例如,如果您正在检查 text/html 响应中的数据,那么编写的开销不会太大

soup = bs4.BeautifulSoup(content, 'html.parser')
assert soup.select_one('h1#title-headliner') == '<h1>title</h1>'

root = lxml.etree.parse(io.StringIO(content), lxml.etree.HTMLParser())
assert next(root.xpath('//h1[@id='title-headliner']')).text == 'title'

不仅仅是

assert 'title' in content

然而,调用解析器更为显式(您不会意外地测试例如 head 中页面元数据中的标题)并且还对数据完整性进行隐式检查(例如您知道有效负载确实是有效的 HTML,因为已成功解析)。

以您的示例为例:如果是 RSS 提要,我将简单地使用 XML 解析器:

from lxml import etree

def test_feed_title(client):
    uri = reverse('my-feed')
    resp = client.get(uri)
    root = etree.parse(io.BytesIO(resp.content))
    title = root.xpath('//channel/title')[0].text
    assert title == 'my title'

在这里,我使用 lxml这是 stdlib 的 xml 的一个更快的实现。将内容解析为 XML 树的优点还在于解析器从字节串中读取,注意编码处理 - 因此您不必自己解码任何内容。

或者使用类似 atoma 的高级内容这是一个很好的 API,专门用于 RSS 实体,因此您不必与 XPath 选择器作斗争:

import atoma

@pytest.mark.django_db
def test_feed_title(client):
    uri = reverse('my-feed')
    resp = client.get(uri)
    feed = atoma.parse_atom_bytes(resp.content)
    assert feed.title.value == 'my title'

  1. ...When is it a good practice to do this vs. using selenium?

简短的回答 - 你不需要它。在阅读您的问题时我并没有太在意,而在撰写评论时我已经想到了 HTML 页面。关于这个 selenium 的评论 - 这个库处理所有低级的东西,所以当测试开始积累计数时(通常,它们做得很快),写

uri = reverse('news-feed')
resp = client.get(uri)
root = parser.parse(resp.content)
assert root.query('some-query')

并且拖动导入变得太麻烦了,所以 selenium 可以用

代替它
driver = WebDriver()
driver.get(uri)
assert driver.find_element_by_id('my-element').text == 'my value'

当然,使用自动浏览器实例进行测试还有其他优势,例如准确查看用户在真实浏览器中会看到的内容、允许页面执行客户端 javascript 等。当然,所有这些主要适用于 HTML 页面测试;在针对 RSS 提要进行测试的情况下,selenium 的使用有点矫枉过正,而 Django 的测试工具绰绰有余。

关于python - pytest-django:这是用参数测试 View 的正确方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56510841/

相关文章:

python - 在 Python 3 中从推文中解码表情符号

python - apt-get 的需求文件,类似于 pip

ruby-on-rails - Wordpress 能否被 Django 或 Ruby on Rails 等框架取代?

python - 将 OpenCV 与 Django 结合使用

python - py.test - 如何在 funcarg/fixture 中使用上下文管理器

python - 查询 : Why is my regex code not reading all characters?

python - 将脚本从 Linux 更改为 Python - 自动化

jquery - 在 Django 中如何传递 JSON 数据以用于 Ajax/jQuery?

python - 为什么 unittest.Test Cases 看不到我的 pytest fixtures?

python - 如何使用带有选项卡完成功能的 python 调试器运行 pytest?