I am trying to write unit tests for my import service that implemented using maatwebsite/excel package. but I cant make it work it always fails! I already read the package doumentaion about test but its not clear to me.
here is my controller method :
public function store(ImportEmployeeRequest $request)
{
try {
EmployeeFacade::importEmployees($request->file('file'));
return response()->json('Your file is importing. The rows have errors will logged on import_failed channel!', Response::HTTP_OK);
} catch (\Throwable $throwable) {
throw new ImportFailedException('File import failed.', Response::HTTP_INTERNAL_SERVER_ERROR, $throwable);
}
}
Here is the service:
class EmployeeService
{
public function __construct(protected EmployeeRepositoryInterface $employeeRepository)
{ }
public function importEmployees($file)
{
$filePath = $this->uploadFile($file);
return ProcessEmployeeImportJob::dispatch(Storage::disk('public')->path($filePath));
}
private function uploadFile($file)
{
$file_name = $file->getClientOriginalName();
$path = 'employee/excel';
$filePath = Storage::disk('public')->putFileAs(
$path,
$file,
$file_name
);
return $filePath;
}
}
here is the importJob:
public function handle(): void
{
$import = new EmployeesImport();
$import->import($this->file);
if($import->failures()->isNotEmpty())
{
foreach ($import->failures() as $failure) {
Log::info($failure->row());
}
}
}
Here is the import class:
public function model(array $row)
{
try {
return new Employee([
'employee_id' => $row['emp_id'],
'username' => $row['user_name'],
'name_prefix' => $row['name_prefix'],
'first_name' => $row['first_name'],
'middle_initial' => $row['middle_initial'],
'last_name' => $row['last_name'],
'gender' => $row['gender'],
'email' => $row['e_mail'],
'date_of_birth' => Carbon::createFromFormat('m/d/Y', $row['date_of_birth'])->format('Y-m-d'),
'time_of_birth' => Carbon::createFromFormat('h:i:s A', $row['time_of_birth'])->format('H:i:s'),
'age_in_years' => $row['age_in_yrs'],
'date_of_joining' => Carbon::createFromFormat('m/d/Y', $row['date_of_joining'])->format('Y-m-d'),
'age_in_company' => $row['age_in_company_years'],
'phone_no' => $row['phone_no'],
'place_name' => $row['place_name'],
'country' => $row['county'],
'city' => $row['city'],
'zip' => $row['zip'],
'region' => $row['region'],
]);
} catch (\Exception $exception) {
// Handle the exception (log it or perform any other action)
return null; // Return null so this row is skipped
}
}
public function rules(): array
{
return [
'emp_id' => ['required', 'numeric','unique:employees,employee_id'],
'user_name' => ['required', 'string', 'min:3', 'max:50','unique:employees,username'],
'name_prefix' => ['required', 'string', 'min:1', 'max:20'],
'first_name' => ['required', 'string', 'min:1', 'max:50'],
'middle_initial' => ['required', 'string', 'min:1', 'max:10'],
'last_name' => ['required', 'string', 'min:1', 'max:50'],
'gender' => ['required', 'string', "in:M,F"],
'e_mail' => ['required', 'email', 'min:4', 'max:150'],
'date_of_birth' => ['required', 'string','regex:/^(0?[1-9]|1[0-2])\/(0?[1-9]|[12][0-9]|3[01])\/\d{4}$/'],
'time_of_birth' => ['required', 'string', 'regex:/^((0?[1-9]|1[0-2]):([0-5][0-9]):([0-5][0-9]) (AM|PM))$/'] ,
'age_in_yrs' => ['required', 'numeric'],
'date_of_joining' => ['required', 'string','regex:/^(0?[1-9]|1[0-2])\/(0?[1-9]|[12][0-9]|3[01])\/\d{4}$/'],
'age_in_company_years' => ['required', 'numeric'],
'phone_no' => ['required', 'string','regex:/^\d{3}-\d{3}-\d{4}$/'],
'place_name' => ['required', 'string', 'min:1', 'max:50'],
'county' => ['required', 'string', 'min:1', 'max:50'],
'city' => ['required', 'string', 'min:1', 'max:50'],
'zip' => ['required','regex:/\b\d{4,5}\b/'],
'region' => ['required', 'string', 'min:1', 'max:50'],
];
}
public function chunkSize(): int
{
return 1000;
}
public function batchSize(): int
{
return 1000;
}
public function onFailure(Failure ...$failures)
{
foreach ($failures as $failure){
Log::channel('import_failed')->error($failure->row());
Log::channel('import_failed')->error($failure->attribute());
Log::channel('import_failed')->error($failure->errors());
Log::channel('import_failed')->error($failure->values());
}
}
and here is the importTest :
public function test_employees_can_be_imported()
{
Excel::fake();
$this->get('/employee/import/csv');
// $import = new EmployeesImport();
// $import->import('employee/excel/import.csv');
Excel::assertQueued('employee/excel/import.csv', 'public');
Excel::assertQueued('employee/excel/import.csv', 'public', function(EmployeesImport $import) {
return true;
});
// When passing the callback as 2nd param, the disk will be the default disk.
Excel::assertQueued('employee/excel/import.csv', function(EmployeesImport $import) {
return true;
});
}
the test always fails and errors:
FAILED Tests\Unit\EmployeeImportTest > employees can be imported
import.csv is not stored on disk public
Failed asserting that an array has the key 'import.csv'.
Any suggestion or clue to lead me write couple up unit tests for the import process will be appreciated. Thank you all :)