Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/250.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在PHPunit中实现双重测试(模拟测试),我遗漏了什么?_Php_Mocking_Phpunit - Fatal编程技术网

如何在PHPunit中实现双重测试(模拟测试),我遗漏了什么?

如何在PHPunit中实现双重测试(模拟测试),我遗漏了什么?,php,mocking,phpunit,Php,Mocking,Phpunit,我可能在这里遗漏了一些非常琐碎的东西,但我无法让phpunit在模拟类中使用stand 下面是一个示例,Foo是我正在测试的类,Bar是我想要模拟的类 我希望下面的示例能够通过,因为我已经模拟了Bar,将Bar::heavy\u-lifting去掉以返回“not-Bar”,然后调用该槽Foo::do\u-stuff()。 但它失败了,示例仍然返回“bar”,似乎完全忽略了我的存根 class Foo { public function do_stuff() { $b = new Ba

我可能在这里遗漏了一些非常琐碎的东西,但我无法让phpunit在模拟类中使用stand

下面是一个示例,
Foo
是我正在测试的类,
Bar
是我想要模拟的类

我希望下面的示例能够通过,因为我已经模拟了
Bar
,将
Bar::heavy\u-lifting
去掉以返回“not-Bar”,然后调用该槽
Foo::do\u-stuff()
。 但它失败了,示例仍然返回“bar”,似乎完全忽略了我的存根

class Foo {
  public function do_stuff() {
    $b = new Bar();
    return $b->heavy_lifting();
  }
}

class Bar {
  public function heavy_lifting() {
    return "bar";
  }
}

class FooTest extends PHPUnit_Framework_TestCase {
  public function testBar() {
    $fake     = "not bar";
    $stand_in = $this->getMock("Bar");
    $stand_in->expects($this->any())
             ->method("heavy_lifting")
             ->will($this->returnValue($fake));

    $foo = new Foo();
    $this->assertEquals($foo->do_stuff(), $fake);
  }
}

您的代码无法按预期工作。存根并不是要替换Bar类,而是要创建可以传递到需要Bar的位置的对象。您应该重构Foo类,如下所示:

class Foo {

    /* inject your dependency to Foo, it can be injected in many ways,
       using constructor, setter, or DI Container */

    public function __construct(Bar $bar) {
        $this->bar = $bar;
    }

    public  function do_stuff() {
        $this->bar->heavy_lifting();
    }

}

然后可以将模拟条传递给类Foo。

任何使用
new
的代码都会直接导致测试困难。把它移到工厂或DI容器中。在我的实现中,Foo是唯一一个受酒吧和重物搬运困扰的人;在您的示例中,来电者突然需要为酒吧而烦恼。这是否打破了“说而不问”的原则,即外界需要尽可能少地了解酒吧的内部情况?嗯,有很多原则,其中一些原则在某种程度上相互矛盾。在DI思想中,总是“让调用方提供所有依赖项,不应该存在隐藏的依赖项”。换句话说,若类有任何依赖项,那个么所有依赖项都必须通过API清晰可见,在我们的示例中是通过构造函数。@berkes“调用者突然需要为Bar而烦恼”。是的,我同意这很糟糕。因此,为该构造函数参数提供一个默认值,它将像当前代码一样创建一个Bar对象。然后,您的测试代码将成为唯一指定该参数的代码。(顺便说一句,正如Jasir的代码注释所说,使用construtor参数只是一种方法;关键是您可以设置一个
$this->bar