以下示例将最好地说明我的问题:
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());
}
}
让我指出,我无法控制定义/包含类'a'的位置。
答案 0 :(得分:1)
你可以消除你的依赖:
首先,您创建一个界面,列出您需要的所有方法:
interface Doer {
function a();
}
然后为您创建一个适配器类:
class ADoer implements Doer
{
protected $dependencyA;
public function __construct(A $dep) {
$this->dependencyA = $dep;
}
public function a() {
$this->dependencyA->a();
}
}
现在让你的B类依赖于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();
答案 1 :(得分:1)
如果您更改了类b,以便可以传入a的实例:
class b
{
function b($a = null)
{
if ($a == null) {
$a = new a();
}
return $a->a() . ' Bar';
}
}
...然后进行测试,您可以使用像Mockery这样的框架来传递一个模拟的' a'总是会回归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