I am attempting to test an image importer which takes a file and submits a form with that image attached. That part of the test seems to be the part where it is falling over and i'm not sure how to resolve it.
I understand the concept of not "mocking what you don't own", however without acknowledging the call to the private method insertImageThroughForm
the test does not work.
I get the following error:
75 ! imports image assets
method call:
- submit(["file" => ["assetFile" => ["file" => Symfony\Component\HttpFoundation\File\UploadedFile:0000000027d380bc00007f8c6cad27ec Object (
'test' => false
'originalName' => 'picco.jpg'
'mimeType' => 'application/octet-stream'
'size' => null
'error' => 0
)]]], false)
on Double\Symfony\Component\Form\Form\P22 was not expected, expected calls were:
- submit(exact(["file" => ["assetFile" => ["file" => Double\Symfony\Component\Finder\SplFileInfo\P19:0000000027d3807500007f8c6cad27ec Object (
'objectProphecy' => Prophecy\Prophecy\ObjectProphecy Object (*Prophecy*)
'relativePath' => null
'relativePathname' => null
)]]]), exact(false))
- submit(exact(["file" => ["assetFile" => ["file" => Double\Symfony\Component\Finder\SplFileInfo\P20:0000000027d3803000007f8c6cad27ec Object (
'objectProphecy' => Prophecy\Prophecy\ObjectProphecy Object (*Prophecy*)
'relativePath' => null
'relativePathname' => null
)]]]), exact(false))
ImageImporterSpec.php
const TEMP_PATH = '/tmp/crmpicco/imageImporter';
function it_imports_image_assets(
Category $category,
AssetFactory $assetFactory,
Asset $asset,
Finder $finder,
SplFileInfo $file1,
SplFileInfo $file2,
FormFactory $formFactory,
Form $form
) {
$category->getId()->willReturn(14);
$createTempPathFilesystem = new Filesystem();
$createTempPathFilesystem->mkdir(self::TEMP_PATH);
$createTempPathFilesystem->mkdir(self::TEMP_PATH . DIRECTORY_SEPARATOR . 'courses');
$imageImportPath = self::TEMP_PATH . DIRECTORY_SEPARATOR . 'courses/';
$createTempPathFilesystem->touch($imageImportPath . 'picco.jpg');
$createTempPathFilesystem->touch($imageImportPath . 'morton.jpg');
$finder->files()->willReturn($finder);
$finder->in($imageImportPath)->willReturn($finder);
$finder->getIterator()->willReturn(new \ArrayIterator([
$file1->getWrappedObject(),
$file2->getWrappedObject(),
]));
$file1->getPathname()->willReturn($imageImportPath . 'picco.jpg');
$file2->getPathname()->willReturn($imageImportPath . 'morton.jpg');
$assetFactory->createForCategory(14)->willReturn($asset);
$formFactory->create('category_asset', $asset, ['csrf_protection' => false])->willReturn($form);
$form->submit(['file' => ['assetFile' => ['file' => $file1->getWrappedObject()]]], false)->shouldBeCalled();
$form->submit(['file' => ['assetFile' => ['file' => $file2->getWrappedObject()]]], false)->shouldBeCalled();
$this->importImageAssets('courses/', $category)->shouldBeCalled();
}
ImageImporter.php
public function importImageAssets($importDirectory, Category $category)
{
$finder = new Finder();
$finder->files()->in($importDirectory);
if (count($finder) > 0) {
foreach ($finder as $image) {
$filename = $image->getBasename('.' . $image->getExtension());
$filepath = $importDirectory . '/' . $image->getFilename();
$asset = $this->assetFactory->createForCategory($category->getId());
$asset->setName($filename);
$this->insertImageThroughForm($asset, $filepath);
$this->entityManager->persist($asset);
}
$this->entityManager->flush();
}
}
private function insertImageThroughForm(Asset $asset, $filePath)
{
$form = $this->formFactory->create('category_asset', $asset, ['csrf_protection' => false]);
$uploadedFile = new UploadedFile($filePath, basename($filePath));
$form->submit(['file' => ['assetFile' => ['file' => $uploadedFile]]], false);
}
What you're testing is more an integration test than a unit test. PhpSpec is not suitable for integration tests, but only for low unit tests. Why it's an integration test? Because you use a real filesystem which is external service and also few 3rd party libraries like Filesystem
and Finder
.
You're trying to mock the Finder
but the Finder
is directly initialized within the method so can't be mocked. You need to inject the Finder
as a dependency of the class.