Django - 如何使用request.FILES进行单元测试post请求

20
我在我的视图中有以下逻辑:
def view_function(request):
    if request.method == 'POST':
        uploadform = UploadFileForm(request.POST, request.FILES)
        if uploadform.is_valid():
            #do stuff

UploadFileForm指的是:

class UploadFileForm(forms.Form):
    file = forms.FileField()

我正在尝试为这个视图编写单元测试。在Django文档中,建议的方法是:

class test_stuffTest(TestCase):
    def setUp(self):
        self.client = django.test.client.Client()
    ...
    def test_stuff(self):
        myfile = open('....\file.csv','r')
        response = self.client.post('/', {'name':'file.csv','attachment':myfile})
        #check response

我的目标是让uploadform.is_valid()评估为True,这样我就可以测试跟随表单验证的代码。当我运行上面的测试时,uploadform.is_valid()评估为False。我是否遗漏了什么?我的测试代码是否将文件添加到request.FILES中,还是做了其他事情?


如果您不确定request.FILES中包含什么内容,最快的方法是在视图中添加一个打印语句以查看发生了什么。 - Alasdair
我尝试过了,但是打印输出中没有包括FILES参数。有开启它的设置吗? - vasek1
3个回答

44

Django测试套件的方式是:

from django.core.files.uploadedfile import SimpleUploadedFile
f = SimpleUploadedFile("file.txt", b"file_content")

这种方法无需创建临时文件并向其写入内容,也不需要模拟文件(这并不像听起来那么容易)。


非常感谢。我尝试使用请求工厂来模拟传入文件。只需将您的代码替换值,并在第一次尝试中就成功了。 - hectorcanto
2
谢谢,你救了我一次模拟文件的麻烦!对于Python3 django 1.10的更新,我必须在文件内容之前加上b,像这样:f = SimpleUploadedFile("file.txt", b"file_content"),因为会出现TypeError。 - redacted

22

文档中文件字段被称为attachment,但在你的代码中被称为file

你的提交数据中也不需要name,因为它是指另一个字段name,而不是上传的文件名。

尝试以下操作:

def test_stuff(self): 
    myfile = open('....\file.csv','r') 
    response = self.client.post('/', {'file':myfile})

3
也许我在这里漏掉了什么,但听起来像是一个好的模拟库的工作。我个人非常喜欢Mock。但是,我属于那些认为你的单元测试应该没有任何外部依赖关系(比如必须在某个特定位置有一个名为“file.csv”的文件等)的阵营。

整洁的库。我之前不知道它,但一定会仔细研究。谢谢! - vasek1
2
已经宣布将把Mock添加到Python的标准库中,学习它可能是一件好事。这里有一个由Michael Foord(Mock的原始作者)在去年的PyCon上发布的视频。http://blip.tv/pycon-us-videos-2009-2010-2011/pycon-2011-testing-with-mock-4899484 还有一个来自今年PyCon的演讲视频,我认为非常不错。http://pyvideo.org/video/699/testing-and-django - 我建议你们都去看看。 - David S

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接