如何测试方法调用一个继承的方法?

时间:2012-03-27 13:37:30

标签: php tdd

考虑以下课程:

class MyClass
{
    public function foo()
    {

    }
}

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

如何使用Mockery测试bar()方法调用foo()方法的事实?

5 个答案:

答案 0 :(得分:1)

我认为在这种情况下你不应该使用模拟框架。

模拟框架用于为测试对象与之交互的所有对象插入测试双精度。即它们用于隔离测试对象。<​​/ p>

您的示例是对实施的测试..通常是脆弱的。

编写一个测试来验证bar的公共结果 - 而不是通过调用foo来完成它的工作。寻找如果bar完成其工作将会发生的世界中可观察到的变化。这样,如果您明天重构bar()以通过其他实现执行相同的工作,您的测试将不会中断。

答案 1 :(得分:0)

我的英语很差,我可能不太明白你的意思,但是:

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 );

答案 2 :(得分:0)

我实际上走了另一条路。我将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();
    }
}

答案 3 :(得分:0)

我发现你已经设法解决了你的问题,但作为参考,这可能是最新的嘲弄代码。

通过mock方法创建模拟时,索引数组被视为构造函数args,因此mockery实际上使用它的魔法扩展了类并创建了一个实例。

ShouldDeferMissing告诉mockery让它的父类(SubClass)处理对Mockery没有被告知要模拟的任何方法的调用。

这仍然是一个小实验,我刚刚意识到如果你试图传递快速期望它不起作用,但我会尝试为此修复。

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

答案 4 :(得分:0)

我刚刚在几天前找到了如何使用最新版本的Mockery,Dave Marshall也暗示了(但有点不同)。

假设我有一个Database类,其中包含列出表,删除表和获取数据库模式的方法,我想创建使用这3种方法的“reset”方法。 这就是我用Mockery嘲笑它的方式。

<?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方法,我嘲笑getSchemalistTablesdropTable:     

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);时执行的实际实现。