0

在 PHP 项目中,我有主单例和其他一些使用主单例的单例:

<?php

class SingletonMain
{
    // Main singleton
    // ...
}

class SingletonA
{
    protected $main;

    function __construct()
    {
        $main = SingletonMain::getInstance();
    }
}

class SingletonB
{
    protected $main;

    function __construct()
    {
        $main = SingletonMain::getInstance();
    }
}
?>

我想,也许在SingletonASingletonB中模拟SingletonMain的最简单方法是获取对SingletonMain实例的引用并执行以下操作:

  1. SingletonMain实例复制到$temp.
  2. MockSingletonMain实例代替SingletonMain。“就地”是指在同一个参考位置,以便SingletonASingletonB可以立即使用新的模拟,就好像它是原始的SingletonMain一样。
  3. 测试。
  4. 从原位恢复SingletonMain实例。$temp

那有可能吗?如果不是,那么在所有SingletonsABCD中模拟SingletonMain的最简单方法是什么......

$this->main = $my_mock目前,我唯一想到的解决方案是在每个叶子单例中显式设置新的模拟,并最终使用正常的赋值运算符(并在测试之后)再次恢复它$this->main = SingletonMain::getInstance()

编辑

通过阅读几个答案,我意识到,我需要提供更多信息。我有大约 20-30 个这样的叶子单例。该应用程序在几年前并不是为了测试而设计的,所以现在我正在寻找绕过单例模式的最佳方法,而不会破坏任何东西并尽可能少地改变。

4

3 回答 3

0

您可以通过创建测试存根来做到这一点:

class SingletonAStub extends SingletonA
{

    public function getMain() {
        return $this->main;
    }

    public function setMain($main) {
        $this->main = $main;
    }
}

在您的测试中,您使用存根,根据需要更改“单例”并进行测试。

当然,最好不要直接使用单例,因此您不需要创建仅用于测试的特殊子类型。

于 2012-10-10T20:02:56.833 回答
0

SingletonA 在您的代码中不是单例,因此您可以轻松地在测试中传递模拟的 SingletonMain 实例:

class SingletonA
{
    protected $main;

    function __construct($main = null)
    {
        if (!$main) $main = SingletonMain::getInstance();
        $this->main = $main;
    }
}

如果没有传递回退到当前行为。

于 2012-10-10T19:36:33.170 回答
0

听起来你需要的是继承。像这样:

class SingletonA extends SingletonMain {
    // Your code specific to SingletonA here.
}

class SingletonB extends SingletonMain {
    // Your code specific to SingletonB here.
}
于 2012-10-10T19:39:55.420 回答