在命名构造函数中创建文件

时间:2016-04-07 19:14:09

标签: php phpspec named-constructor

我有一个通过命名构造函数创建文件的类,但是当我使用phpspec测试它时,它不会创建文件。

我无法找到原因,所以我想重新审视一下我的代码可能有所帮助。

这是我的文件类:

<?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));
    }
}

1 个答案:

答案 0 :(得分:2)

这是因为在需要这样做之前,phpspec不会实例化该类。只有针对原始类本身的方法调用或期望(即should*)才会导致实例化,而beConstructedThrough只是提示如何 phpspec应该获得的一个实例。

现在,您可以通过调用某种方法或者甚至只是调用$this->shouldHaveType(File::class)来解决这个问题,但我建议重新考虑这种方法。如果您最终集成到外部 - 无论是SDK,文件系统,数据库等,那么您最好不要编写集成测试。无论如何,你在这种情况下非常接近(嘲笑不应该是必要的)。 phpspec更倾向于指定类和方法的行为/逻辑。描述副作用并不真正适合它的范围。这里使用assert()也是一个暗示,因为这对于phpspec支持的规范来说当然不是惯用的。

对于集成测试,PHPUnit是一个更好的选择,因为它更通用..所以你可以根据需要灵活地实例化和断言。