问题
I am building a file upload JSON API with Lumen and trying to write phpunit API tests.
The problem I am having though is that as soon as I try to simulate a file upload with a real image constructed like ["file" => new UploadedFile(TestUtils::tempPath('test.jpg'), 'test.jpg', "image\jpeg", 100, null, true)]
and sending it via $this->json('POST', '/chunk', $data);
,
I can't do anything with the uploaded file because it is an array and I get the error Call to a member function move() on array in ...
Oddly enough if I use UploadedFile::fake()->image('test.jpg')
it mangles my request and the other data I send with it isn't available in the controller.
If I dd the file object in my controller, it shows an "array(0){}". I am thinking it has something to do with the transfer via json('POST'), as unit tests that use an UploadedFileObject directly run successfully.
If I dd the entire request, it shows:
["request"]=>
object(Symfony\Component\HttpFoundation\ParameterBag)#52 (1) {
["parameters":protected]=>
array(5) {
["chunkType"]=>
string(4) "flow"
["flowIdentifier"]=>
string(13) "Testing123Bnu"
["flowChunkNumber"]=>
int(1)
["flowTotalChunks"]=>
int(2)
["file"]=>
array(0) {
}
}
}
...
["files"]=>
object(Symfony\Component\HttpFoundation\FileBag)#71 (1) {
["parameters":protected]=>
array(0) {
}
}
...
["content":protected]=> string(103) "{(otherData..), "file":{}}"
I have no idea how to circumvent this or test a file upload in this situation and have been searching for hours. The symfony test mode in the UploadedFile constructor has no effect.
Here is my test:
public function testChunkUpload_FlowChunk()
{
$data = [ (otherData)
"file" => new UploadedFile(TestUtils::tempPath('test.jpg'), 'test.jpg', "image\jpeg", 100, null, true)
//UploadedFile::fake()->image('test.jpg')
];
$this->assertFileExists(TestUtils::tempPath('test.jpg'));
$this->json('POST', '/chunk', $data);
$this->assertEquals(200, $this->response->status());
$this->assertEquals('application/json', $this->response->headers->get('Content-Type'));
}
And here is the relevant method in my controller:
public function receiveChunk(Request $request){
if (! $request->has('chunkType')) {
return response()->json(["Invalid Chunk Type"], 400);
}
$data = $this->chunkNormalizer->normalizeInput($request->all());
$chunk = $this->chunkFactory->createChunk( (otherData)
$data['fileHandle']);
$this->fileAssembler->processChunk($chunk);
return response()->json(["Success"], 200);
}
And the error occurs in processChunk:
public function processChunk(FileChunk $chunk){
...
$chunkName = "..." . ".chunk";
$fileHandle = $chunk->getFileHandle();
$fileHandle->move($this->assemblePath, $chunkName);
}
Any ideas would be greatly appreciated!
回答1:
EDIT: Strangely enough, in the laravel docs the "json" method is used instead of "call" as well. Could this be an error? Or just a Lumen incompatability issue? (Laravel Docs)
I have figured out how to get the test to run. My assumptions about how the file is uploaded through the JS vendor library were wrong. In fact, the file chunks are uploaded with a XmlHttpRequest "multipart/formdata" and NOT as JSON.
I understood the error (JSON encoding), but not the source. After understanding that it uses an XmlHttpRequest, the fix was simple.
Working test:
public function testChunkUpload_FlowChunk()
{
$data = [ (otherData)
"file" => new UploadedFile(TestUtils::tempPath('test.jpg'), 'test.jpg', "image\jpeg", 100, null, true)
//UploadedFile::fake()->image('test.jpg')
];
$this->assertFileExists(TestUtils::tempPath('test.jpg'));
$this->call('POST', '/chunk', $data);
$this->assertEquals(200, $this->response->status());
$this->assertEquals('application/json', $this->response->headers->get('Content-Type'));
}
I am still unsure about why using UploadedFile::fake()->image("xyz.jpg") had a different effect, now the test runs with both methods.
来源:https://stackoverflow.com/questions/46485894/lumen-5-5-json-api-file-upload-test-breaks-with-uploadedfile