gpt4 book ai didi

php - PropelORM、Symfony 2 和单元测试

转载 作者:搜寻专家 更新时间:2023-10-31 20:49:31 25 4
gpt4 key购买 nike

习惯这样写的习惯:

$results = SomeModelQuery::create()->filterByFoo('bar')->find();

然而,这不能扩展到单元测试,因为我不能注入(inject)模拟对象,即我不能影响返回的数据。我想使用夹具数据,但我不能。

注入(inject)对象也不是很好:

class Foo
{
public __construct($someModelQuery)
{
$this->someModelQuery = $someMOdelQuery;
}

public function doSthing()
{
$results = $this->someModelQuery->filterByFoo('bar')->find();
}
}

DI 感觉很糟糕。我有数十个查询对象要模拟和抛出。通过构造函数进行设置既丑陋又痛苦。 using 方法的设置是错误的,因为调用时可能会忘记。总是为每个库和操作手动创建这些查询对象感觉很痛苦。

我如何优雅地使用 PropelORM 查询类进行 DI?我不想调用如下方法:

$oneQuery = OneQuery::create();
$anotherQuery = AnotherQuery::create();
// ... 10 more ...
$foo = new Foo($oneQuery, $anotherQuery, ...);
$foo->callSomeFunctionThatNeedsThose();

最佳答案

在我看来(和 Martin Folowers's )在静态调用所有内容和使用依赖注入(inject)之间有一个步骤,这可能就是您正在寻找的。

在我无法进行完整 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());
}
}

我给出了一个调用真实查询代码和模拟查询代码的示例。

因此,这使您能够注入(inject)模拟,而无需将每个依赖项注入(inject)到您想要进行单元测试的类中。

上面的代码有很多种写法。将其用作概念证明并根据您的需要进行调整。

关于php - PropelORM、Symfony 2 和单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9664670/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com