是否可以用普通 PHP 或 Mockery 覆盖 class 的方法?

Is it possible to override method of the class with plain PHP or Mockery?

我的问题最好用下面的例子来说明:

class a
{
    function a()
    {
         return file_get_contents('http://some/third/party/service');
    }
}

class b
{
    function b()
    {
        $a = new a();
        return $a->a() . ' Bar';
    }
}

class testB extends test
{
    function testB()
    {
        $b = new b();

        // Here we need to override a::a() method in some way to always return 'Foo'
        // so it doesn't depend on the third party service. We only need to check
        // the $b::b() method's behavior (that it appends ' Bar' to the string).
        // How do we do that?

        $this->assert_equals('Foo Bar', $b->b());
    }
}

请注意,我无法控制 class 'a' defined/included.

的位置

你可以这样消除你的依赖:

首先创建一个界面,其中将列出您需要的所有方法:

interface Doer {
    function a();
}

然后为你创建一个适配器class class:

class ADoer implements Doer
{
   protected $dependencyA;

   public function __construct(A $dep) {
       $this->dependencyA = $dep;
   }

   public function a() {
       $this->dependencyA->a();
   }
}

现在让你的 B class 依赖于 Doer 接口,而不是 A 实现:

class B {
   private $doer;
   public function __construct(Doer $a) {
      $this->doer = $a;
   }

   public function b() {
      $this->doer->a();
   }

   public function setDoer(Doer $a) {
       $this->doer = $a;
   }

   //getDoer()
}

现在可以随意切换了:

class FooDoer implements Doer {
   function a() {
      //do whatever you want
   }

}
$b->setDoer(new FooDoer());
$b->b();

如果您更改了 class b 以便可以传入 a 的实例:

class b
{
    function b($a = null)
    {
        if ($a == null) {
            $a = new a();
        }

        return $a->a() . ' Bar';
    }
}

...然后为了测试,您可以使用像 Mockery 这样的框架来传递 'a' 的模拟实例,它总是 returns 'Foo'

use \Mockery as m;

class testB extends test
{

    public function tearDown()
    {
        m::close();
    }

    public function testB()
    {
        $mockA = m::mock('a');
        $mockA->shouldReceive('a')->times(1)->andReturn('foo');

        $b = new b($mockA);

        $this->assert_equals('Foo Bar', $b->b());
    }

}

在此处查看 Mockery 的完整文档和示例:http://docs.mockery.io/en/latest/getting_started/simple_example.html