如何创建使用特征数组的模拟对象?

时间:2018-08-30 18:04:44

标签: php phpunit

我当前正在使用PHPUnit v5.7.27

我想创建一个使用特征数组的模拟对象。我将如何处理?我只看到getMockForTrait是使用单个特征创建模拟对象的一种方式。我的问题是,特质要求在班级存在另一个特质。

更新:问题的更多背景信息

给出:

trait GetSet {
    public function __call(){ /* does some magic */
}

trait RepositoryAware {
    public function getRepository(string $name)
    {
        /* makes use of the GetSetTrait*/
    }
}

class Controller
{
    use GetSet;
    use RepositoryAware;
}

鉴于PHP的局限性,我不能简单地将use GetSet放在RepositoryAware特征上,因为控制器导入的其他特征也可以带来GetSet特征。此外,控制器类本身可能正在使用GetSet特性提供的行为。

2 个答案:

答案 0 :(得分:0)

我当前的解决方案是创建一个同时导入特征和模拟该类的虚拟类:

class RepositoryAwareClass
{
    use GetSet;
    use RepositoryAware;
}

像这样,我能够正确测试RepositoryAware特性所提供的行为,同时构成GetSet特性的要求。

答案 1 :(得分:0)

模拟概念是基于您将使用依赖项注入的想法构建的。我当然可以理解为什么您可能不想在这种多重继承中使用依赖注入,例如php使用的名为“ Traits”的模型。模拟工具(例如为phpunit构建的工具)用于替代对象实例,而不是类/接口/特征本身。 PHP特性更像是具有静态依赖关系,而不是对对象实例的依赖关系。但是,即使您使用特征并假定特征与类基本相同,根据模拟最佳实践,也应将特征作为自己的测试进行测试,而不是通过另一个类来测试特征。如果您想嘲笑特征本身,您可能想尝试重新审视您的设计,因为我认为这无法完成。您当然可以模拟特征并测试该特征,但是您不能模拟特征然后将其作为对对象的依赖项进行注入。想象一下,例如一个类实现了一个接口,模拟一个特性就等同于模拟一个类实现的接口,这是不可能的。您只能通过基于setter或构造函数的依赖项注入来模拟类所依赖的对象的接口。另一个示例是尝试模拟要测试的类所继承的类。你也不能那样做。也许在javascript世界中,这种类型的东西可能有用,并且从某些人的角度来看很理想,但是我认为,如果要使用模拟,则需要坚持使用object依赖项注入,而不要使用静态{{1} }。

那有什么选择呢?我认为以下示例将是如何在模拟中使用“传统的” OOP做法,以实现不使用继承即可共享功能的目标。该示例还使您的依赖关系更加明确。出于记录,我为您不使用继承而鼓掌。

use

总的来说,我觉得PHP社区向左走了一个疯狂的转折,试图变得更像javascript,我觉得特质可以将您带入一个角落。这是一个很好的例子。至少现在,我真的会避免使用它们。从长远来看,我相信泛型将是您需要通用GetSet代码的更好的解决方案,但是尚未在php中实现泛型:-(。