0

名前付きコンストラクターを介してファイルを作成するクラスがありますが、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));
    }
}
4

1 に答える 1

2

これは、必要になるまで phpspec がクラスをインスタンス化しないためです。元のクラス自体に対するメソッド呼び出しまたは期待 (つまりshould*) のみがインスタンス化され、phpspec がインスタンスを取得する方法についてbeConstructedThroughのヒントにすぎません。

さて、何らかのメソッドを呼び出すか、単に を呼び出すことでこれを回避できますが$this->shouldHaveType(File::class)、アプローチを再考することをお勧めします。SDK、ファイルシステム、データベースなど、最終的に外部のものに統合する場合は、統合テストを作成する方がはるかに優れています。とにかく、この場合はかなり近づいています(モックは実際には必要ありません)。phpspecは、クラスとメソッドの動作/ロジックを指定することをより目的としています..副作用を説明することは、その権限に実際には適合しません。hereの使用assert()は、それに対するヒントでもあります。これは、phpspec に裏打ちされた仕様では確かに慣用的ではないためです。

統合テストの場合は、より汎用的な PHPUnit を選択することをお勧めします。そのため、必要に応じてインスタンス化とアサートを柔軟に行うことができます。

于 2016-04-07T21:44:21.177 に答える