本文共 4946 字,大约阅读时间需要 16 分钟。
文件上传的测试可能会非常棘手,但是通过使用恰当的工具,再掌握一些技巧,这个过程可以会更加高效,也能更容易。\
如果你之前没有了解过的话,那么简单来讲,它允许与保存在内存中的文件进行交互,而不是与机器中实际存在文件进行交互。这样做的好处在于我们并不需要删除用于测试的文件,如果测试失败,teardown或者其他用于移除测试文件的代码没有执行,那么这就更会成为一个问题了。除此之外,因为它处理的是内存而不是物理的硬件驱动器,所以它会更快。简而言之,它能够更加整洁,速度也会更快。\
本文将会创建一个端点(路由)来上传包含用户信息的CSV文件,并测试CSV文件中的用户能够展现到一个JSON格式的响应中,同时还会添加校验功能,确保所处理的文件是CSV类型。这是一个超出现实的样例,不过它可以作为一个很好的起点,帮助你在项目中实现类似的功能。\
在本文中,我们假设你已经安装好了Laravel(我们所使用的是5.3版本)。你不用实际去点击这个路由,但是我们建议你使用或。在这个指南中,不会包含如何让它们就绪并运行起来的内容,通过这个仓库的中,你可以获取本文所对应的代码。\
打开控制台并导航至项目的根文件夹(在这里你可以看到composer.json文件和.env文件等内容),如果你运行:
composer require mikey179/vfsStream --dev\
那么就会将vfsStream拉取到composer file文件的development部分中,同时还会拉取所需的文件,从而能够在测试中使用这个包。完成这些之后,我们就为测试做好了准备。\
为了让这个过程尽可能简单,只需在tests文件夹(同样在项目的根目录下)中创建一个名为UploadCsvTest.php的文件。现在,我们需要打开这个文件并将如下的内容添加进去。
\u0026lt;?php\\class UploadCsvTest extends TestCase\{\ public function testSuccessfulUploadingCsv()\ {\\ }\\}\
首先,我们让文件上传运行起来,然后可以再回过头来再添加校验功能。采取这种方式的原因在于,我们能够为可运行的代码迭代式地添加功能。例如,如果你能上传文件的话,那么它就是可运行的代码,为其添加校验是对功能的增强,可以稍后再进行。\
现在,添加如下的代码到“testSuccessfullUploadingCsv”函数中:
$this-\u0026gt;json('POST', 'upload-new-users-csv', ['usersCsvFile' =\u0026gt; 'someFile']);\$this-\u0026gt;assertResponseOk();\
如果通过控制台运行(稍后,我们将会通过PHPUnit来引用这条命令)下面的命令的话:
phpunit --filter=UploadCsvTest\
不出意料,这里会发生失败,看起来会像如下所示:
Expected status code 200, got 404.\Failed asserting that false is true.\
404响应意味着无法找到路由,现在我们来定义它。导航至routes/web.php文件(从上一个Laravel版本开始,路由文件已经从Http目录转移到了这里),并且在文件的底部添加下面的代码:
Route::post('/upload-new-users-csv', function (\\Illuminate\\Http\\Request $request) {\\});\
现在,如果我们运行PHPUnit的话,测试就能通过了。所以,接下来我们就应该在路由文件的闭包中访问预期的文件了。因此,回到这个文件中,并在闭包中添加如下这行代码:
$request-\u0026gt;input('usersCsvFile')-\u0026gt;openFile();\
此时,路由看起来如下所示:
Route::post('/upload-new-users-csv', function (\\Illuminate\\Http\\Request $request) {\ $request-\u0026gt;input('usersCsvFile')-\u0026gt;openFile();\});\
现在,如果你运行PHPUnit的话,会得到另外的错误,这是一个500错误。在这里,要查清发生了什么需要一点技巧。我们可以在测试中通过如下的方式来查看响应的内容:
dd($this-\u0026gt;response-\u0026gt;getContent());\
但是很重要的一点在于,它要在断言响应OK之前执行,否则的话,在我们得到dd输出之前,测试就已经失败了。另外一种方式就是查看位于“storage/logs/laravel.log”中的日志。不管采用哪种检查方式,我们都会看到类似于这样的信息:“使用字符串的形式调用了成员函数openFile()”,这其实就是我们要达到的效果,因为在测试中,当我们发起post请求时,发送的是一个字符串。接下来,该看一下vfs了!\
它并不全面,但这是一个好的开端,这是一个非常深入和强大的包。为了让测试看起来更棒一些,我们先将创建文件的内容放到一个函数中。所以,回到测试文件(UploadCsvTest.php)中,将其修改成如下所示:
\u0026lt;?php \\use Illuminate\\Http\\UploadedFile;\use org\\bovigo\\vfs\\vfsStream;\\class UploadCsvTest extends TestCase\{\ public function testSuccessfulUploadingCsv()\ {\ $this-\u0026gt;json('POST', 'upload-new-users-csv', ['usersCsvFile' =\u0026gt; $this-\u0026gt;createUploadFile()]);\ $this-\u0026gt;assertResponseOk();\ }\\ protected function createUploadFile()\ {\ $vfs = vfsStream::setup(sys_get_temp_dir(), null, ['testFile' =\u0026gt; 'someString']);\\ return new UploadedFile(\ $vfs-\u0026gt;url().'/testFile',\ null,\ 'text/csv',\ null,\ null,\ true\ );\ }\}\
这里引入了很多内容,首先是vfsStream::setup,它会在内存中创建一个文件。样例中使用了“sys_get_temp_dir()”,这只是让它看起来“更真实一些”,这里可以使用任意的值,比如可以将其修改为字符串“root”,运行效果是完全一样的。这背后的理念是允许你创建任意的目录结构以适应实际的需求。\
这其实并不太重要,因为PHP会自动将上传的文件放到系统的临时目录中,所以只需使用“sys_get_temp_dir()”就可以,在这个场景中,它其实并没有什么关系。下一个参数用来设置文件权限,在本例中,我们没有特殊的要求,所以只需将其设置为null,这样允许你对文件进行任意操作。最后,是目录(本例中也就是“/tmp”)中的内容,它只是一个数组,由文件名(key)和值(现在是普通的字符串,不过后续需要改为CSV内容)所组成。\
最后,我们可以看到的是UploadedFile,它是对Symfony的UploadedFile的扩展,我们按顺序快速看一下它的参数(来源于Symfony的注释内容):\
第一个参数:文件的完整临时目录;
第二个参数:原始的文件名;
第三个参数:PHP所提供的文件类型,如果是null的话,默认为application/octet-stream;
第四个参数:文件大小;
第五个参数:上传出现错误的常量(PHP的UPLOAD_ERR_XXX常量之一),如果是null的话,默认为UPLOAD_ERR_OK;
第六个参数:是否启用测试模式。\
如果你运行PHPUnit的话,那么测试就能够通过了!现在,我们让文件看起来更真实一些,在createUploadFile函数中,将它的内容改为如下所示:
protected function createUploadFile()\{\ $vfs = vfsStream::setup(sys_get_temp_dir(), null, ['testFile.csv' =\u0026gt; '']);\\ $uploadFile = new UploadedFile(\ $vfs-\u0026gt;url().'/testFile.csv',\ null,\ 'text/csv',\ null,\ null,\ true\ );\\ collect([\ ['username', 'first name', 'last name'],\ ['jondoe', 'Jon', 'Doe'],\ ['janedoe', 'Jane', 'Doe']\ ])-\u0026gt;each(function ($fields) use ($uploadFile) {\ $uploadFile-\u0026gt;openFile('a+')-\u0026gt;fputcsv($fields);\ });\\ return $uploadFile;\}\
这里利用了Laravel的集合辅助工具,借助一些PHP的功能来填充文件。openFile()会得到底层的,然后直接使用它,将数组中的元素添加到文件中,就像CSV文件中的某行数据一样。运行PHPUnit,我们依然会得到绿色的测试通过提示。现在,我们要确保能够得到预期的结果,响应中的JSON要列出文件中的内容。要实现这项功能,将testSuccessfulUpload函数改成如下所示:
public function testSuccessfulUploadingCsv()\{\ $this-\u0026gt;json('POST', 'upload-new-users-csv', ['usersCsvFile' =\u0026gt; $this-\u0026gt;createUploadFile()])\ -\u0026gt;seeJson([\ \"username,\\\"first name\\\
转载地址:http://ojbnl.baihongyu.com/