考虑以下课程:
class MyClass
{
public function foo()
{
}
}
class SubClass extends MyClass
{
public function bar()
{
$this->foo();
}
}
如何使用Mockery测试bar()
方法调用foo()
方法的事实?
答案 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
方法,我嘲笑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);
时执行的实际实现。