pytest-django:这是用参数测试视图的正确方法吗?
pytest-django: Is this the right way to test view with parameters?
假设我正在 Django 应用程序中测试 RSS 提要视图,我应该这样做吗?
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)
reverse
-ing 然后将其传递到 client.get()
是正确的测试方法吗?我认为它比简单地 .get()
ing URL.
更干燥,更面向未来
我应该这样断言 dummy_object
在响应中吗?
我在这里使用响应对象的 str
表示进行测试。什么时候这样做与使用 selenium
比较好?我知道它可以更容易地验证所说的 obj
或 属性(例如 dummy_object.title
)是否封装在 H1
标签中。另一方面,如果我不关心 how obj 是如何表示的,那么像上面那样做会更快。
重新评估我的评论(没有仔细阅读问题并忽略了 RSS 提要内容):
- 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 的角度来看,您正在测试您的视图,而不关心它们映射到的确切端点。因此,使用 reverse
是 IMO 明确而正确的方法。
- Should I assert that
dummy_object
is in the response this way?
这里要注意了。 response.content
是字节串,因此断言 dummy_object.title in str(resp.content)
是危险的。考虑以下示例:
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 树的优点还在于解析器从字节串中读取,注意编码处理 - 因此您不必自己解码任何内容。
或者使用 high-level 之类的 atoma
,它非常适合 RSS 实体 API,因此您不必与 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'
- ...When is it a good practice to do this vs. using
selenium
?
简答 - 您不需要它。我在阅读您的问题时没有太在意,在撰写评论时脑子里想着 HTML 页。关于这个 selenium
的评论——这个库处理所有 low-level 的东西,所以当测试开始积累计数时(通常,它们做得很快),写
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'
当然,使用自动浏览器实例进行测试还有其他优势,例如准确查看用户在真实浏览器中会看到的内容,允许页面执行 client-side javascript 等。当然,所有其中主要适用于 HTML 页面测试;在针对 RSS 提要进行测试的情况下 selenium
使用 Django 的测试工具绰绰有余。
假设我正在 Django 应用程序中测试 RSS 提要视图,我应该这样做吗?
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)
reverse
-ing 然后将其传递到client.get()
是正确的测试方法吗?我认为它比简单地.get()
ing URL. 更干燥,更面向未来
我应该这样断言
dummy_object
在响应中吗?我在这里使用响应对象的
str
表示进行测试。什么时候这样做与使用selenium
比较好?我知道它可以更容易地验证所说的obj
或 属性(例如dummy_object.title
)是否封装在H1
标签中。另一方面,如果我不关心 how obj 是如何表示的,那么像上面那样做会更快。
重新评估我的评论(没有仔细阅读问题并忽略了 RSS 提要内容):
- Is
reverse
-ing and then passing that into theclient.get()
the right way to test? I thought it's DRYer and more future-proof than simply.get()
ing the URL.
我同意这一点 - 从 Django 的角度来看,您正在测试您的视图,而不关心它们映射到的确切端点。因此,使用 reverse
是 IMO 明确而正确的方法。
- Should I assert that
dummy_object
is in the response this way?
这里要注意了。 response.content
是字节串,因此断言 dummy_object.title in str(resp.content)
是危险的。考虑以下示例:
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 树的优点还在于解析器从字节串中读取,注意编码处理 - 因此您不必自己解码任何内容。
或者使用 high-level 之类的 atoma
,它非常适合 RSS 实体 API,因此您不必与 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'
- ...When is it a good practice to do this vs. using
selenium
?
简答 - 您不需要它。我在阅读您的问题时没有太在意,在撰写评论时脑子里想着 HTML 页。关于这个 selenium
的评论——这个库处理所有 low-level 的东西,所以当测试开始积累计数时(通常,它们做得很快),写
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'
当然,使用自动浏览器实例进行测试还有其他优势,例如准确查看用户在真实浏览器中会看到的内容,允许页面执行 client-side javascript 等。当然,所有其中主要适用于 HTML 页面测试;在针对 RSS 提要进行测试的情况下 selenium
使用 Django 的测试工具绰绰有余。