Reputation: 1512
My question would be best illustrated by the following example:
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());
}
}
Let me point out that I don't have the control over where class 'a' is being defined/included.
Upvotes: 0
Views: 1283
Reputation: 481
If you changed class b so that the instance of a can be passed in:
class b
{
function b($a = null)
{
if ($a == null) {
$a = new a();
}
return $a->a() . ' Bar';
}
}
...then for test, you can use a framework like Mockery to pass in a mocked instance of 'a' which always 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());
}
}
See the full docs and examples for Mockery here: http://docs.mockery.io/en/latest/getting_started/simple_example.html
Upvotes: 1
Reputation: 1529
You can eliminate your dependency like that:
First you create an interface that will list all methods you need:
interface Doer {
function a();
}
Then create an adapter class for you a class:
class ADoer implements Doer
{
protected $dependencyA;
public function __construct(A $dep) {
$this->dependencyA = $dep;
}
public function a() {
$this->dependencyA->a();
}
}
Now make your B class depends on Doer interface, not on A implementation:
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()
}
Now you can switch it at will:
class FooDoer implements Doer {
function a() {
//do whatever you want
}
}
$b->setDoer(new FooDoer());
$b->b();
Upvotes: 1