如何在django中unit testingfile upload

在我的Django应用程序中,我有一个完成file upload的视图。核心片段就是这样的

... if (request.method == 'POST'): if request.FILES.has_key('file'): file = request.FILES['file'] with open(settings.destfolder+'/%s' % file.name, 'wb+') as dest: for chunk in file.chunks(): dest.write(chunk) 

我想unit testing的观点。我打算testing愉快的path以及失败的path..其中request.FILES没有关键'文件'的情况下, request.FILES['file']None ..

如何设置快乐path的发布数据?有人可以告诉我吗?

来自Client.post上的Django文档:

提交文件是一个特例。 要发布文件,只需要提供文件字段名称作为密钥,并将文件句柄提供给要上载的文件作为值。 例如:

 c = Client() with open('wishlist.doc') as fp: c.post('/customers/wishes/', {'name': 'fred', 'attachment': fp}) 

我以前with open('some_file.txt') as fp:做同样的事情,但是之后我需要repo中的图片,video和其他真实文件,而且我正在testing一个经过很好testing的Django核心组件的一部分,所以目前这是我一直在做的事情:

 from django.core.files.uploadedfile import SimpleUploadedFile def test_upload_video(self): video = SimpleUploadedFile("file.mp4", "file_content", content_type="video/mp4") self.client.post(reverse('app:some_view'), {'video': video}) # some important assertions ... 

Python 3.5+中,您需要使用bytes对象而不是str 。 将"file_content"更改为b"file_content"

它一直工作正常, SimpleUploadedFile创build一个InMemoryFile行为像一个常规的上传,你可以select名称,内容和内容types。

我build议你看看Django的RequestFactory 。 IT是模拟请求中提供的数据的最佳方法。

说,我发现你的代码有几个缺陷。

  • “单位”testing意味着只testing一个function单位的“单位”。 所以,如果你想testing这个视图,你会testing视图和文件系统,而不是unit testing。 为了使这一点更清楚。 如果您运行该testing,并且视图正常工作,但您没有权限保存该文件,则testing将因此失败。
  • 其他重要的是testing速度 。 如果你正在做TDD这样的testing,那么执行testing的速度就非常重要。 访问任何I / O不是一个好主意

所以,我build议你重构你的视图来使用如下的函数:

 def upload_file_to_location(request, location=None): # Can use the default configured 

并做一些嘲笑。 你可以使用Python模拟 。

PS:你也可以使用Django testing客户端但是这意味着你要添加更多的东西来testing,因为客户端使用会话,中间件等。没有类似的unit testing。

我为自己的事件相关的应用程序做这样的事情,但是你应该有足够多的代码来处理你自己的用例

 import tempfile, csv, os class UploadPaperTest(TestCase): def generate_file(self): try: myfile = open('test.csv', 'wb') wr = csv.writer(myfile) wr.writerow(('Paper ID','Paper Title', 'Authors')) wr.writerow(('1','Title1', 'Author1')) wr.writerow(('2','Title2', 'Author2')) wr.writerow(('3','Title3', 'Author3')) finally: myfile.close() return myfile def setUp(self): self.user = create_fuser() self.profile = ProfileFactory(user=self.user) self.event = EventFactory() self.client = Client() self.module = ModuleFactory() self.event_module = EventModule.objects.get_or_create(event=self.event, module=self.module)[0] add_to_admin(self.event, self.user) def test_paper_upload(self): response = self.client.login(username=self.user.email, password='foz') self.assertTrue(response) myfile = self.generate_file() file_path = myfile.name f = open(file_path, "r") url = reverse('registration_upload_papers', args=[self.event.slug]) # post wrong data type post_data = {'uploaded_file': i} response = self.client.post(url, post_data) self.assertContains(response, 'File type is not supported.') post_data['uploaded_file'] = f response = self.client.post(url, post_data) import_file = SubmissionImportFile.objects.all()[0] self.assertEqual(SubmissionImportFile.objects.all().count(), 1) #self.assertEqual(import_file.uploaded_file.name, 'files/registration/{0}'.format(file_path)) os.remove(myfile.name) file_path = import_file.uploaded_file.path os.remove(file_path) 

在Django 1.7中,TestCase有一个问题,可以通过使用open(filepath,'rb')来解决,但是当使用testing客户端时,我们无法控制它。 我认为最好确保file.read()总是返回字节。

来源: https ://code.djangoproject.com/ticket/23912,由KevinEtienne

没有rb选项,会引发TypeError:

 TypeError: sequence item 4: expected bytes, bytearray, or an object with the buffer interface, str found