编程语言
首页 > 编程语言> > php-PropelORM,Symfony 2和单元测试

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