Как проверить метод вызывает унаследованный метод? - PullRequest
0 голосов
/ 27 марта 2012

Учитывая классы ниже:

class MyClass
{
    public function foo()
    {

    }
}

class SubClass extends MyClass
{
    public function bar()
    {
        $this->foo();
    }
}

Как я могу проверить с помощью Насмешка тот факт, что метод bar() вызывает метод foo()?

Ответы [ 5 ]

1 голос
/ 28 марта 2012

Я думаю, что в этом случае вы не должны использовать фальшивые рамки.

Фреймворковые фреймворки используются для слота в двойниках теста для всех объектов, с которыми взаимодействует испытуемый.т. е. они используются для изоляции испытуемого.

Ваш пример - тест реализации ... который обычно хрупок.

Напишите тест, чтобы проверить общедоступный результат bar, а не то, что он выполняет свою работу, вызывая foo для себя.Ищите наблюдаемое изменение в мире, которое произойдет, если бар сделает свою работу.Таким образом, если вы выполните рефакторинг bar () завтра, чтобы выполнить ту же работу через какую-то другую реализацию, ваши тесты не сломаются.

0 голосов
/ 25 октября 2012

Я только что нашел несколько дней назад, как это сделать с последней версией Mockery, на что намекал и Дэйв Маршалл (но немного по-другому).

Давайте предположим, что у меня есть класс Database с методами для составления списка таблиц, удаления таблицы и получения схемы базы данных, и я хочу создать метод «reset», который использует эти 3 метода. Вот как я издевался над ним с помощью насмешек.

<?php
class Database
{
    public function getSchema($version = null)
    {
        //...
    }

    public function listTables()
    {
        //...

    }

    public function dropTable($table)
    {
        //...
    }

    public function reset($version = null)
    {
        $tables = $this->listTables();
        foreach ($tables as $table)
        {
            $this->dropTable($table);
        }

        $schema = $this->getSchema($version);
        foreach ($schema as $query)
        {
            $this->conn->query($query);
        }

    }
}

Итак, чтобы проверить метод reset, описанный выше, вот как я высмеял getSchema, listTables и dropTable:

class DatabaseTest extends \PHPUnit_Framework_TestCase
{
    //...

    public function test_reset_list_existing_tables_deletes_them_then_create_a_new_schema()
    {
        $app = new \Silex\Application();

        $ConnectionMock = \Mockery::mock('\Doctrine\DBAL\Connection');
        $ConnectionMock
            ->shouldReceive('query')
            ->with('SQL query 1')
            ->once()
            ->ordered('reset');
        $ConnectionMock
            ->shouldReceive('query')
            ->with('SQL query 2')
            ->once()
            ->ordered('reset');
        $app['db'] = $ConnectionMock;

        $Database = \Mockery::mock('\Database[listTables,dropTable, getSchema]', array($app));
        $Database
            ->shouldReceive('listTables')
            ->once()
            ->ordered('reset')
            ->andReturn(array('system', 'users'));
        $Database
            ->shouldReceive('dropTable')
            ->with('system')
            ->once()
            ->ordered('reset');
        $Database
            ->shouldReceive('dropTable')
            ->with('users')
            ->once()
            ->ordered('reset');
        $Database
            ->shouldReceive('getSchema')
            ->with(1)
            ->once()
            ->ordered('reset')
            ->andReturn(array('SQL query 1', 'SQL query 2'));

        $Database->reset(1);
    }
}

В частности, посмотрите, как я создаю макет:

$Database = \Mockery::mock('\Database[listTables,dropTable, getSchema]', array($app));

Я перечисляю метод, который хочу смоделировать, в «[]» и передаю конструктор Database в виде массива во втором параметре mock.

reset, который я хочу проверить, не является поддельным, так что фактическая реализация выполняется, когда я выполняю $Database->reset(1);.

0 голосов
/ 25 октября 2012

Я вижу, что вам удалось решить вашу проблему, но для справки, это возможно с последним издевательским кодом.

При создании макета с помощью метода mock индексированный массив принимается в качестве аргумента конструктора, поэтому насмешка фактически расширяет ваш класс магией и создает экземпляр.

ShouldDeferMissing сообщает издевательству, чтобы его родительский класс (SubClass) обрабатывал вызовы любых методов, которые издевались над издевательством.

Это все еще немного экспериментально, и я только что понял, что это не сработает, если вы попытаетесь оправдать быстрые ожидания, но я постараюсь исправить это.

use Mockery as m;

class MyClass
{
    public function foo()
    {
        return 'foo';
    }
}

class SubClass extends MyClass
{
    public function bar()
    {
        return $this->foo();
    }
}

$subClass = new SubClass;
echo $subClass->bar() . PHP_EOL; // foo


$mock = m::mock("SubClass", array())->shouldDeferMissing();
echo $mock->bar() . PHP_EOL; // foo

$mock->shouldReceive("foo")->andReturn("bar");
echo $mock->bar() . PHP_EOL; // bar
0 голосов
/ 29 марта 2012

Я на самом деле выбрал другую дорогу.Я переместил метод foo() в новый класс, протестировал этот класс и передал его классу SubClass посредством внедрения зависимостей.Таким образом, я смог смоделировать новый класс и убедиться, что метод foo() был вызван правильно:

class NewClass
{
    public function foo()
    {

    }
}

class SubClass
{
    public $NewClass;

    public function __construct(NewClass $NewClass)
    {
        $this->NewClass = $NewClass;
    }

    public function bar()
    {
        $this->NewClass->foo();
    }
}
0 голосов
/ 27 марта 2012

Мой английский довольно плохой, возможно, я не совсем понимаю, что вы имеете в виду, но:

class MyClass
{
    public function foo()
    {
        echo "this is foo";
    }
}

class SubClass extends MyClass
{
    public function bar()
    {
        $this->foo();
    }
}

$test = new subClass();
$test->bar();

$class = new ReflectionClass('SubClass');
Reflection::export( $class );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...