0

特定のファイルの拡張子に基づいてライター戦略を返す Factory クラスがあります。

public static function getWriterForFile($file)
{
    // create file info object
    $fileInfo = new \SplFileInfo($file);
    // check that an extension is present
    if ('' === $extension = $fileInfo->getExtension()) {
        throw new \RuntimeException(
            'No extension found in target file: ' . $file
        );
    }
    // build a class name using the file extension
    $className = 'MyNamespace\Writer\Strategy\\'
        . ucfirst(strtolower($extension))
        . 'Writer';
    // attempt to get an instance of the class
    if (!in_array($className, get_declared_classes())) {
        throw new \RuntimeException(
            'No writer could be found for the extension: ' . $extension
        );
    }
    $instance = new $className();
    $instance->setTargetFile($file);
    return $instance;
}

私の戦略はすべて同じインターフェースを実装しています。たとえば、次のようになります。

class CsvWriter implements WriterStrategyInterface
{
    public function setTargetFile($file)
    {
        ...
    }

    public function writeLine(array $data)
    {
        ...
    }

    public function flush()
    {
        ...
    }
}

テストが既存の特定の戦略に依存しないように、ダミーの拡張機能を使用してこのメ​​ソッドをテストできるようにしたいと考えています。クラス名を設定してインターフェイスのモックを作成しようとしましたが、これはモック クラス名を宣言していないようです。

public function testExpectedWriterStrategyReturned()
{
    $mockWriter = $this->getMock(
        'MyNamespace\Writer\Strategy\WriterStrategyInterface',
        array(),
        array(),
        'SssWriter'
    );

    $file = 'extension.sss';

    $writer = MyNamespace\Writer\WriterFactory::getWriterForFile($file);

    $this->assertInstanceOf('MyNamespace\Writer\Strategy\WriterStrategyInterface', $writer);;
}

ファクトリをロードするためのモック ライター戦略をステージングする方法はありますか、またはファクトリ メソッドをリファクタリングしてテストしやすくする必要がありますか?

4

1 に答える 1

5

そのファクトリの主な目的と責任は、オブジェクトの作成です。

私見あなたはそれをテストする必要があります

$this->assertInstanceOf('class', $factory->getWriterForFile($file));

なぜもっと抽象化しないのですか?

ファクトリがオブジェクトの作成を別のクラスにディスパッチするような方法で実装することができます。

以下を行う「オブジェクトクリエーター」を持つ:

$class = new ReflectionClass($class);
$instance = $class->newInstanceArgs($args);

またはそれらの線に沿ったものですが、「テストは単体テストのように見えます」以外に、あなたの利益は何ですか? テスト能力のためだけにコードベースと変更を実際に改善しているのではなく、常に少しおかしなにおいがします。

工場のテストは、すべての工場が実際に機能し、目的のオブジェクトを生成することを確認する統合/配線テストとして扱います。


現在のコード サンプルに対して提案する唯一の変更は、次の 2 つを変更することです。

a) ファクトリ メソッドを非静的にする

正当な理由がない場合は、注入できないことを除いて、静的ファクトリから何も得られず、静的にすることでグローバルスコープからアクセスできるようになるため、ファクトリに依存関係を取得するには、さらに多くのグローバルとすぐ。工場で DI を行う場合、通常、工場を適切なオブジェクトにすることで、今後の問題を回避するのに役立ちます

b) 工場で diskIo を実行しないでください。使用: getWriterForFile(\SplFileInfo $file)

工場はファイルシステムを気にするべきではありません。既存のファイルが必要な場合は、それを必要とし、エラーを処理する方法の詳細を消費者に任せる必要があります。

SplTempFileObjectこれにより、テストが容易になり、実稼働目的であってもファクトリをファイル システムから独立させることができるという利点があります。

于 2013-01-09T02:15:21.040 に答える