I created the following example test case:
<?php
abstract class Model
{
//...
public static function factory($data)
{
$className = get_called_class();
$obj = new $className($data);
return $obj;
}
}
class User extends Model
{
}
class ExampleController
{
protected $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function create()
{
return $this->user->factory(array('name' => 'Jim'));
}
}
class ExampleTest extends PHPUnit_Framework_TestCase
{
public function testSomething()
{
$user = new User(array('name' => 'Jim'));
$modelStub = $this->getMockBuilder('User')
->disableOriginalConstructor()
->getMock();
$modelStub
->method('factory')
->with(array('name' => 'Jim'))
->willReturn($user);
$example = new ExampleController($modelStub);
$this->assertEquals($user, $example->create());
}
}
However I get the following error:
1) ExampleTest::testSomething
PHPUnit_Framework_MockObject_BadMethodCallException:
I seems to work fine when I remove the static
keyword, then my test passes. But I want my Model class to also allow, in other cases, the option to call certain methods without having to instantiate first:
// when instantiation is required
$userModel = new User();
$user = $userModel->factory(array('name' => 'Jim'));
// called statically, no initial instantiation required
$user = User::factory(array('name' => 'Jim'));
I came across this blog which states that methods declared statically, yet called dynamically, is ok. However, methods declared dynamically, yet called statically, will throw a STRICT error - http://www.lornajane.net/posts/2010/declaring-static-methods-in-php
I have also used Laravel's Eloquent before and it appears that both method calls are possible there:
// Eloquent example without initial instantiation is possible too
$user = User::find(1);
Anyway, regardless of whether my code works, I want to be able to mock these methods declared statically. It seems upon reading that PHPUnit just doesn't handle static methods well (I read there was a staticExpects method, but now deprecated as of PHPUnit 3.8). So I'm about to embark on trying some alternative testing frameworks (Codeception and AspectMock, PHPSpec, mockery) as I haven't much experience with others. Would really appreciate some pointers for this issue or advice on the matter as it would really help too in unit testing legacy applications at our company, thanks