如何在Django中模拟用户和请求


75

我有与请求对象或用户对象进行交互的Django代码。例如:

foo_model_instance = models.get_or_create_foo_from_user(request.user)

如果要使用django python shell进行测试或在单元测试中进行测试,您将在其中传递什么?这里只是一个User对象即可,但是对模拟请求对象的需求也经常出现。

对于外壳程序或单元测试:

  • 您如何嘲笑用户?
  • 您如何模拟请求?

2
“您一直在使用该词,但我认为这并不意味着您认为这意味着……”我认为您的意思是“样机”。
Mike DeSimone 2010年

9
@Mike:听起来很有趣,但我认为他做对了。@pax:打败我:(
mpen 2010年

6
我……我必须承认……在我房间的寂静中……深夜……我……是的,是的!我嘲笑用户!他们全部!@perrierism:我们不是在取笑您,我们只是在享受您美妙的单词选择。
彼得·罗威尔

Answers:


84

对于请求,我将使用Django随附的RequestFactory

from django.test.client import RequestFactory
rf = RequestFactory()
get_request = rf.get('/hello/')
post_request = rf.post('/submit/', {'foo': 'bar'})

对于用户,我将按照@ozan的建议使用django.contrib.auth.models.User,并可能与factory boy提速(对于factory boy,您可以选择不保存到DB)


1
既然RequestFactory可用,这绝对是正确的答案。归功于Ozan的回答(实例化真实对象是足够且可取的)。我没有使用过Factory Boy,但是如果它接近Rail的Factory Girl的质量,那么看起来它将是一个不错的选择。
Purrell 2014年

在Django迁移脚本中为我工作的最佳解决方案。但是,需要request.user设置当前版本。同样也可以像普通视图一样使用此请求,很高兴可以将其包含request.csrf_processing_done = True在就绪请求中(通过CSRF检查)
garmoncheg 2015年

51

您如何嘲笑用户?

初始化一个django.contrib.auth.models.User对象。User.objects.create_user使这变得容易。

您如何模拟请求?

初始化一个 django.http.HttpRequest对象。

当然,根据您要执行的操作有一些快捷方式。如果您只需要一个对象,该对象具有user指向用户的属性,则只需创建任何内容(任何内容)并将其赋予该属性即可。


2
@ S.Lott有时使用真实的东西是很好的,但是随着项目的发展,它最终会非常缓慢。可以在几秒钟而不是几分钟内运行模拟测试真是太好了。
TM。

1
@TM:也许这通常是正确的。但是Django客户端确实非常快。您是否有其他选择和一些基准来显示节省的时间?
S.Lott

@ S.Lott只是我自己的项目的经验。使用内置用户的替代方法是仅使用pymox框架之类的东西,或者使用与此处一些答案中建议的相同的API创建自己的模拟对象。使用实际的请求对象不是速度问题。
TM。

11
@ S.Lott我并不是说客户端运行缓慢,也不是说模拟比客户端快(我假设“客户端”是指djangos虚拟网站“浏览器”)。我是说它们比数据库访问快(这仅适用User于此问题的一部分)。如果您不认为模拟比实际访问数据库要快,那么我怀疑您实际上并没有尝试和比较过。在一个很小的项目中,当我们更改代码以模拟模型时,我们的团队从测试套件花费了1.5分钟到不到5秒。如果差距太大,则无需编写基准。
TM。

1
我的真实要求有一个.user属性。实例django.http.HttpRequest没有。创建后,我只是设置request.user。看起来合理吗?
乔纳森·哈特利'02

7

您可以按照Anurag Uniyal的建议滚动自己的模拟,也可以使用模拟框架。

回应那些说法,就像在Django中一样,您可以创建一个普通用户...我建议这样做会破坏单元测试的目的。单元测试不应该涉及数据库,但是通过创建用户,您已经更改了数据库,因此我们为什么要模拟一个数据库。


2
正如Daniel所提到的,测试运行器为您创建然后销毁了一个测试数据库,因此您不必为此担心。
ozan 2010年

4
除非您使用的是数据库,否则它不再是单元测试。它可能仍然是完全有效的集成测试,但不是单元测试。
迈克尔·威廉姆森

1
问题在于创建和销毁数据库需要时间。每次进行更改时,我都希望眨眼之间就能运行数千个测试。我不想建立一个数据库和一个应用程序实例来运行我的测试。
蒂姆·奥汀格

同意,进行不打入数据库的测试非常有用。即使您使用的是SQLite数据库,其速度仍然比使用模拟的测试慢。
TM。


5

您无需模拟用户,因为您可以在测试中创建一个用户-测试完成后数据库将销毁。

要模拟请求,请使用Simon Willison的此代码段


我同意您通常可以为测试创建用户的机会-有时您不希望这样做-或这样做超出了测试范围。如果我正在测试,如果辅助方法返回False,则拒绝该权限-将其耦合到数据库是错误的。该辅助方法存在,因为我不想了解数据库表示形式。
yarbelk 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.