PHPUnit Ложные объекты и статические методы - PullRequest
45 голосов
/ 01 марта 2010

Я ищу лучший способ тестирования следующего статического метода (в частности, с использованием модели Doctrine):

class Model_User extends Doctrine_Record
{
    public static function create($userData)
    {
        $newUser = new self();
        $newUser->fromArray($userData);
        $newUser->save();
    }
}

В идеале я бы использовал фиктивный объект, чтобы гарантировать, что «fromArray» (с предоставленными пользовательскими данными) и «save» были вызваны, но это невозможно, поскольку метод является статическим.

Есть предложения?

Ответы [ 6 ]

43 голосов
/ 01 марта 2010

Себастьян Бергманн, автор PHPUnit, недавно опубликовал в блоге сообщение о Stubbing и Mocking Статические методы . С PHPUnit 3.5 и PHP 5.3, а также последовательным использованием позднего статического связывания, вы можете сделать

$class::staticExpects($this->any())
      ->method('helper')
      ->will($this->returnValue('bar'));

Обновление: staticExpects равно устарело с PHPUnit 3.8 и будет полностью удалено в более поздних версиях.

11 голосов
/ 20 февраля 2014

Теперь есть библиотека AspectMock, чтобы помочь с этим:

https://github.com/Codeception/AspectMock

$this->assertEquals('users', UserModel::tableName());   
$userModel = test::double('UserModel', ['tableName' => 'my_users']);
$this->assertEquals('my_users', UserModel::tableName());
$userModel->verifyInvoked('tableName'); 
1 голос
/ 19 ноября 2017

Я бы создал новый класс в пространстве имен модульного теста, который расширяет Model_User, и проверил бы это. Вот пример:

Оригинальный класс:

class Model_User extends Doctrine_Record
{
    public static function create($userData)
    {
        $newUser = new self();
        $newUser->fromArray($userData);
        $newUser->save();
    }
}

Класс Mock для вызова модульных тестов:

use \Model_User
class Mock_Model_User extends Model_User
{
    /** \PHPUnit\Framework\TestCase */
    public static $test;

    // This class inherits all the original classes functions.
    // However, you can override the methods and use the $test property
    // to perform some assertions.
}

В вашем модульном тесте:

use Module_User;
use PHPUnit\Framework\TestCase;

class Model_UserTest extends TestCase
{
    function testCanInitialize()
    {   
        $userDataFixture = []; // Made an assumption user data would be an array.
        $sut = new Mock_Model_User::create($userDataFixture); // calls the parent ::create method, so the real thing.

        $sut::test = $this; // This is just here to show possibilities.

        $this->assertInstanceOf(Model_User::class, $sut);
    }
}
0 голосов
/ 25 июля 2018

Библиотека duplit также может помочь вам проверить статические методы:

/* Create a mock instance of your class */
$double = Doublit::mock_instance(Model_User::class);

/* Test the "create" method */
$double::_method('create')
   ->count(1) // test that the method is called once
   ->args([Constraints::isInstanceOf('array')]) // test that first argument is an array
   ->stub('my_value') // stub the method to return "myvalue"
0 голосов
/ 10 июля 2016

Другой возможный подход с библиотекой Moka :

$modelClass = Moka::mockClass('Model_User', [ 
    'fromArray' => null, 
    'save' => null
]);

$modelClass::create('DATA');
$this->assertEquals(['DATA'], $modelClass::$moka->report('fromArray')[0]);
$this->assertEquals(1, sizeof($modelClass::$moka->report('save')));
0 голосов
/ 01 марта 2010

Тестирование статических методов обычно считается немного сложным (как вы, наверное, уже заметили) , особенно до PHP 5.3.

Не могли бы вы изменить свой код, чтобы не использовать статический метод? На самом деле я не понимаю, почему вы используете статический метод; это, вероятно, может быть переписано в некоторый нестатический код, не так ли?


Например, может ли что-то подобное не сработать:

class Model_User extends Doctrine_Record
{
    public function saveFromArray($userData)
    {
        $this->fromArray($userData);
        $this->save();
    }
}

Не уверен, что вы будете тестировать; но, по крайней мере, больше нет статического метода ...

...