单元测试动态工厂类

时间:2015-09-22 15:32:52

标签: php unit-testing phpunit

我有一个构建在另一个框架之上的应用程序。所述框架具有许多值对象,我需要使用装饰器模式以各种方式扩展它们。让我们调用基础对象实体和装饰器类Wrappers。同一类的实体可以具有不同的“类型”,并且每种类型都需要不同的Wrapper类来公开特定于该类型的功能。此应用程序不是最后一层,不控制存在哪些类型或使用哪些类(在链的上方完成),因此赋值需要是动态的。

我创建了一个工厂类,它接收一个实体并为它确定正确的包装器。可以为工厂分配一个Wrapper类,以便在实体具有给定类型时使用。

<?php

class WrapperFactory
{
    protected $default_wrapper = null;
    protected $typed_wrappers = [];

    public function __construct($default){
        $this->setDefaultWrapper($default);
    }

    public function setDefaultWrapper($class){
        if ($this->validateWrapperClass($class)){
            $default_wrapper = $class;
        }
    }

    public function getDefaultWrapper(){
        return $this->$default_wrapper;
    }

    public function setWrapperForType($class, $type){
        if($this->validateWrapperClass($class)){
            $this->$typed_wrappers[$type] = $class;
        }
    }

    public function hasWrapperForType($type){
        return array_key_exists($type, $this->typed_wrappers);
    }

    public function getWrapperForType($type){
        if($this->hasWrapperForType($type)){
            return $this->typed_wrappers[$type];
        }
        else{
            return $this->getDefaultWrapper();
        }
    }

    public function wrap($entity)
    {
        $class = $this->getWrapperForType($entity->type);
        return new $class($entity);
    }

    protected function validateWrapperClass($class){
        if(class_exists($class) && class_implements($class, WrapperInterface::class)){
            return true;
        }else{
            throw new BadMethodCallException("Wrapper must implement ". WrapperInterface::class . ".");
        }
    }
}

我不完全确定如何正确地对这个班级进行单元测试。有没有办法可以模拟实现接口的而不是对象?如何测试分配给类型的类是否正常工作?我是否需要在我的测试文件中显式声明一个或两个虚拟类,或者有办法模拟它们吗?

1 个答案:

答案 0 :(得分:0)

如果您创建一个Mock对象,PHPUnit将创建一个扩展您为其创建的类的类。因为这也适用于接口,所以您只需创建一个接口模拟并获取其类名:

$mock = $this->getMock('WrapperInterface');
$class = get_class($mock);
$this->assertTrue($factory->validateWrapperClass($class));