Answer the question
In order to leave comments, you need to log in
How to test methods that create objects of other classes?
For example, there is such a class where I need to test the someMethod method
class Foo
{
public function someMethod()
{
$bar = new Bar;
$bar->method1();
$bar->method2();
$blabla = $bar->getResult();
//etc
}
}
Answer the question
In order to leave comments, you need to log in
Separate the creation of an instance and its use.
class BarFabric
{
public function create(array $config = [])
{
return new Bar($config);
}
}
class Foo
{
protected $barFabric;
public function __construct(BarFabric $barFabric)
{
$this->barFabric = $barFabric;
}
public function someMethod()
{
$bar = $this->barFabric->create();
$bar->method1();
$bar->method2();
$blabla = $bar->getResult();
//etc
}
}
class FooTest
{
public function testSomeMethod()
{
$bar = \Mokery::mock(Bar::class);
// ... описание поведения для мока
$factory = \Mokery::mock(BarFactory::class);
$factory->shouldReceive('create')->andReturn($bar);
$foo = new Foo($factory);
$this->assertSomething($foo);
}
}
class FooQuery extend ActiveQuery
{
/**
* @inheritdoc
* @return Foo[]|array
*/
public function all($db = null)
{
return parent::all($db);
}
/**
* @inheritdoc
* @return Foo|array|null
*/
public function one($db = null)
{
return parent::one($db);
}
}
class Bar
{
protected $query;
public function __construct(FooQuery $query)
{
$this->query = $query;
}
public function someMethod()
{
$foo = $this->query->where(...)->one();
$foo->doSomething();
}
}
$queryMock = \Mockery::mock(FooQuery::class);
$queryMock->shouldRecieve('where->one')->andReturn($fooMock);
$fooMock = \Mockery::mock(Foo::class.'[save, update]');
$fooMock->shouldRecieve('save', 'update')->andReturn(true);
$foo = new Foo();
$foo->populateRelation('bar', new Bar());
You should not initialize the Bar object in the someMethod method, instead use the Dependency Injection pattern. This way, firstly, fewer dependencies are created, and secondly, such a construction is easier to test: in a unit test, you simply add the Bar mock through injection. I personally prefer constructor injection in Yii2, but that's more of a matter of taste.
As a matter of fact, matperez implemented exactly this pattern.
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question