php-PropelORM,Symfony 2和单元测试
作者:互联网
我习惯于这样写的习惯:
$results = SomeModelQuery::create()->filterByFoo('bar')->find();
但是,这不能用于单元测试,因为我无法注入模拟对象,即我无法影响返回的数据.我想使用灯具数据,但不能.
注入对象似乎也不是一件好事:
class Foo
{
public __construct($someModelQuery)
{
$this->someModelQuery = $someMOdelQuery;
}
public function doSthing()
{
$results = $this->someModelQuery->filterByFoo('bar')->find();
}
}
DI感觉很恐怖.我有数十个要模拟和抛出的查询对象.通过构造函数进行设置非常丑陋且痛苦.使用method设置是错误的,因为在调用时可能会忘记它.总是为每个单独的库和操作手动创建这些查询对象感到很痛苦.
我如何用PropelORM查询类进行DI处理?我不想调用类似的方法:
$oneQuery = OneQuery::create();
$anotherQuery = AnotherQuery::create();
// ... 10 more ...
$foo = new Foo($oneQuery, $anotherQuery, ...);
$foo->callSomeFunctionThatNeedsThose();
解决方法:
在我看来(和Martin Folowers’s),在静态调用所有内容和使用依赖注入之间存在一个步骤,这可能正是您要查找的.
在无法执行完整DI的地方(例如Zend Framework MVC),我将使用服务定位器.服务层将是您所有类从那里获得依赖项的地方.可以将其视为类依赖的一层深度抽象.使用服务定位器有很多好处,但是在这种情况下,我将重点介绍可测试性.
我们来看一些代码,这是模型查询类
class SomeModelQuery
{
public function __call($method, $params)
{
if ($method == 'find') {
return 'Real Data';
}
return $this;
}
}
除非调用方法“ find”,否则它只会返回自身.然后将返回硬编码字符串“ Real Data”.
现在我们的服务定位器:
class ServiceLocator
{
protected static $instance;
protected $someModelQuery;
public static function resetInstance()
{
static::$instance = null;
}
public static function instance()
{
if (self::$instance === null) {
static::$instance = new static();
}
return static::$instance;
}
public function getSomeModelQuery()
{
if ($this->someModelQuery === null) {
$this->someModelQuery = new SomeModelQuery();
}
return $this->someModelQuery;
}
public function setSomeModelQuery($someModelQuery)
{
$this->someModelQuery = $someModelQuery;
}
}
这有两件事.提供一个全局范围方法实例,以便您始终可以使用它.并允许将其重置.然后为模型查询对象提供get和set方法.如果尚未设置,请使用延迟加载.
现在执行实际工作的代码:
class Foo
{
public function doSomething()
{
return ServiceLocator::instance()
->getSomeModelQuery()->filterByFoo('bar')->find();
}
}
Foo调用服务定位器,然后从中获取查询对象的实例,并对该查询对象进行所需的调用.
所以现在我们需要为所有这些编写一些单元测试.这里是:
class FooTest extends PHPUnit_Framework_TestCase
{
protected function setUp()
{
ServiceLocator::resetInstance();
}
public function testNoMocking()
{
$foo = new Foo();
$this->assertEquals('Real Data', $foo->doSomething());
}
public function testWithMock()
{
// Create our mock with a random value
$rand = mt_rand();
$mock = $this->getMock('SomeModelQuery');
$mock->expects($this->any())
->method('__call')
->will($this->onConsecutiveCalls($mock, $rand));
// Place the mock in the service locator
ServiceLocator::instance()->setSomeModelQuery($mock);
// Do we get our random value back?
$foo = new Foo();
$this->assertEquals($rand, $foo->doSomething());
}
}
我给出了一个示例,其中调用了真正的查询代码,并在其中模拟了查询代码.
因此,这使您能够注入模拟,而无需将每个依赖项注入到要进行单元测试的类中.
有许多方法可以编写上述代码.将其用作概念证明并使其适应您的需求.
标签:propel,unit-testing,symfony,phpunit,php 来源: https://codeday.me/bug/20191201/2082167.html