У меня есть класс, который создает файл через именованный конструктор, но когда я тестирую его с помощью phpspec, он не создает файл.
Я не могу найти причину этого, поэтому я думаю, что новый взгляд на мой код может помочь.
Вот мой класс File:
<?php
namespace Acme;
class File
{
/**
* @var Path
*/
private $path;
/**
* @var FileName
*/
private $fileName;
private function __construct(Path $path, FileName $fileName)
{
$this->path = $path;
$this->fileName = $fileName;
}
public static function create(Path $path, FileName $fileName)
{
if (file_exists((string) $path . (string) $fileName)) {
throw new \DomainException('File already exists');
}
if (!touch((string) $path . (string) $fileName)) {
throw new \DomainException('Cannot create file');
}
return new self($path, $fileName);
}
}
Вот моя спецификация:
<?php
namespace spec\Acme;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Acme\Path;
use Acme\FileName;
class FileSpec extends ObjectBehavior
{
private $testPath;
private $existingFileName = 'existingFile.extension';
private $nonExistingFileName = 'nonExistingFile.extension';
private $existingFilePath;
private $nonExistingFilePath;
function let()
{
$this->testPath = sys_get_temp_dir() . '/';
$this->existingFilePath = $this->testPath . $this->existingFileName;
$this->nonExistingFilePath = $this->testPath . $this->nonExistingFileName;
// Creating existing file
if (!touch($this->existingFilePath)) {
throw new \Exception('Cannot create existing file for testing');
}
// Removes non existing file
if (file_exists($this->nonExistingFilePath)) {
if (!unlink($this->nonExistingFilePath)) {
throw new \Exception('Cannot remove non existing file for testing');
}
}
}
function it_does_not_create_a_file_when_the_file_already_exists(Path $path, FileName $fileName)
{
$path->__toString()->willReturn($this->testPath);
$fileName->__toString()->willReturn($this->existingFileName);
$this->beConstructedThrough('create', [$path, $fileName]);
$this->shouldThrow(new \DomainException('File already exists'))->duringInstantiation();
}
function it_creates_a_new_file_if_file_does_not_exist(Path $path, FileName $fileName)
{
$path->__toString()->willReturn($this->testPath);
$fileName->__toString()->willReturn($this->nonExistingFileName);
$this->beConstructedThrough('create', [$path, $fileName]);
assert(file_exists($this->nonExistingFilePath));
}
}
Это связано с тем, что phpspec не будет создавать экземпляр класса до тех пор, пока это не потребуется. Только вызовы метода или ожидания (т.е. should*
) против самого исходного класса приведет к его созданию, и beConstructedThrough
это просто намек на то, чтобы как это phpspec должен получить экземпляр.
Теперь вы можете обойти это, вызвав какой-то метод, или, возможно, просто вызов $this->shouldHaveType(File::class)
, но я бы предложил переосмыслить подход. Если вы в конечном итоге интеграции во что-то внешнее — будь то SDK, файловая система, база данных и т. д., вам будет гораздо лучше написать интеграция тестовое задание. В любом случае, в этом случае вы достаточно близки (издеваться не нужно). phpspec больше нацелен на определение поведения / логики классов и методов .. описание побочных эффектов не совсем вписывается в его компетенцию. Использование assert()
Здесь также есть подсказка, так как это, конечно, не является идиоматическим для спецификаций, поддерживаемых phpspec.
Для интеграционного теста PHPUnit будет лучшим выбором, так как он более универсален, поэтому у вас будет гибкость для создания экземпляров и утверждения по мере необходимости.
Других решений пока нет …