I'm using Laravel 5.7 and have this controller
public function upload(Request $request)
{
$fileData = $request->getContent();
$fileName = uniqid().'.xlsx';
try {
// save file locally
Storage::disk('local')->put($fileName, $fileData);
// dispatch to queue
AnyJob::dispatch($fileName);
// insert in import_statuses table for status checking
AnyModel::create([
'job_id' => $fileName
]);
} catch (\Exception $e) {
error_log($e);
return response()->json([
'error' => 'Could not save file or queue not found.'
], 500);
}
return response()->json([
'status' => 'OK',
'jobId' => $fileName,
]);
}
And I'm trying to create a test that enters the catch, but I can't get it to work.
I already tried mocking Storage
and expect methods disk
and put
to be called, but it always complains about other methods being called and not expected.
I also tried mocking AnyJob
and AnyModel
in many ways but that doesn't seem to affect the request made by $this->post
.
This is my test method right now:
public function testUploadException()
{
$xlsxFile = UploadedFile::fake()->create('test.xlsx', 100);
// ignore Storage and Job real work
\Illuminate\Support\Facades\Storage::fake();
$this->withoutJobs();
$mock = Mockery::mock('\App\AnyModel');
$mock
->shouldReceive('create')->times(3)
->andThrow(new \Exception('any error'));
$this->app->instance('\App\AnyModel', $mock);
$response = $this
->withHeaders(['content-type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'])
->post('/api/upload', [$xlsxFile]);
$response
->assertStatus(500)
->assertJson([
'error' => 'Could not save file or queue not found.'
]);
}
And what it returns
root@3e5d84a4db42:/application/api# vendor/bin/phpunit
PHPUnit 7.5.4 by Sebastian Bergmann and contributors.
....F 5 / 5 (100%)
Time: 2.62 seconds, Memory: 20.00MB
There was 1 failure:
1) Tests\Feature\UploadTest::testUploadException
Expected status code 500 but received 200.
Failed asserting that false is true.
/application/api/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestResponse.php:133
/application/api/tests/Feature/UploadTest.php:50
FAILURES!
Tests: 5, Assertions: 8, Failures: 1.
The main reason this isn't going to work is because you're not resolving the Model from the IoC e.g. using app()
or dependency injection. This will work with facades but not Eloquent models.
You can change the controller method definition to the following to resolve the class from the container:
public function upload(Request $request, AnyModel $anyModel)
Then your call to create
would be:
$anyModel->create([
'job_id' => $fileName
]);
There are also a couple of issues in your test as well:
'App\AnyModel'
not '\App\AnyModel'
. I would suggest using ::class instead of using a string i.e. AnyModel::class
(make sure you've imported the class).create()
once so having ->times(3)
will throw an error.