Doctrine orm 你不能强迫我去模仿实体吗?

Doctrine orm 你不能强迫我去模仿实体吗?,doctrine-orm,bdd,phpspec,Doctrine Orm,Bdd,Phpspec,让我们考虑一下这种情况 public class FooManager() { //somewhere in my manager class code public function merge(Foo $a, Foo $b, $id) { if ($a->getId() == $id) { //!! PAY ATTENTION !! } //and so on } } 我几乎在任何地方都读到过,模拟实体不

让我们考虑一下这种情况

public class FooManager()
{
    //somewhere in my manager class code
    public function merge(Foo $a, Foo $b, $id)
    {
        if ($a->getId() == $id) { //!! PAY ATTENTION !!
        }
        //and so on
    }
}
我几乎在任何地方都读到过,模拟实体不是一种好的做法,但我想知道这段特定的代码

如果我不能将Id分配给真实的实体对象(例如,它是由条令自动生成的),我如何在不模拟
Foo
实体的情况下测试此功能

更新 我在思考这个问题,脑海中闪现出一些东西:我在这里测试
FooManager
,而不是实体。所以,对我来说,使用mock并不是唯一的解决方案,甚至可能是最好的。有人可以帮助我了解我的思维过程是否良好

更新2
我之前没有提到它,但是,当然,我需要测试对
$a
$b
的更改(
$a
将从
$b
接收一些属性值,并相应地更新其属性)。这是测试的目标,因为
FooManager
的目标是将
$b
属性合并到
$a
属性中(当然,应用一些逻辑)

如果您需要模拟写测试,创建它是正常的

在这种具体情况下,您需要一个存根。我建议阅读以解释mock和stub之间的区别

罗伯特·C·马丁:模拟跨越建筑上重要的边界,但不在这些边界之内。你可以从这一点开始研究


我的观点是:既然在这种情况下,您需要创建一个用于编写正确测试的模拟,那么就创建它。我看不出这个操作的负面影响。

如果您需要绕过doctrine的自动生成实体id策略,您可以通过元数据进行操作,并设置一个已知id。例如,如果您使用DoctrineFixtureHandle加载测试装置,您的装置中可以有:

class FooFixtures  extends AbstractFixture implements OrderedFixtureInterface
{
    public function load(ObjectManager $manager)
    {

        $metadata = $manager->getClassMetaData("Acme\\DemoBunde\\Entity\\Foo");
        $metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_NONE);
...        
        $foo = new Foo();
        $foo ->setId(3);
        $foo ->setTitle('Foo example');
然后在你的测试课上使用它

public function setUp()
{
    parent::setUp();

    $this->fooFixtures = new FooFixtures();

    $this->loadFixtures(array($this->fooFixtures));
 }
现在数据库中有一个id为3的Foo实例

希望这有助于我理解你的需要

DISCLAMER:用数据库id硬编码测试不是一个好的做法

我能达到的

正如我之前所说,我的第一个想法是创建一个模拟,因为phpspec+理论似乎迫使我这么做

然而,过了一会儿,我经历了一个混乱的过程-
>getFoo()->hasToBeCalled()
->setFoo()->hasToBeCalled()
序列,在这个序列中,
FooManager
所“接触”的所有属性都需要一个预期。这迫使我重新思考这个解决方案,不,对我来说不是最好的

我已经检查了我的类,并且事实上SUT不是我想要在这里直接测试的,但是我需要检查的是这个动作对实体的影响(无论如何是一种行为,对吗?),我决定如下进行:

  • 创建一个
    TestFoo
    实体(位于
    spec\folderToMySpec\FooSpec.php
    内)

    这样,我既可以直接设置
    $id
    (这不是我需要作为原则进行测试的行为,在正常情况下,我会这样做),也可以将这个类保持在我的
    /src
    代码库之外

  • 我修改了我的
    merge()
    函数,只返回我需要检查的实体以进行测试(而且,我并不是为了测试才这样做的,因为有一些关于被合并实体的信息可能会很有用)

  • 最后,对于直接从SUT返回的实体,我可以像通常使用SUT本身一样使用预言匹配器

这个解决方案有很多优点,因为我不需要编写被模拟实体调用的每个方法,并且让我可以自由地使用返回的存根测试我真正需要测试的内容


有什么想法吗?

存根不是一种“特殊”的嘲弄吗?在网上阅读。。。我认为是这样。此外,这对我也没有帮助,我错了吗?在那篇文章中,罗伯特·C·马丁解释了哑巴、存根、间谍、模仿和假货之间的区别。无论如何,测试是主要的。如果您不能将id分配给真实的实体对象,您应该创建存根或模拟以进行测试。谢谢,我重构了我的答案。这很清楚,但根本不是一个解决方案,因为即使没有db数据,我也必须能够测试该过程。此外,如果我使用“真实”实体,我就不能使用prophecy方法来测试值,这就为我指明了一个方向,即mock(或stub)可能是唯一的解决方案(即使我从未将getId()调用到我的管理器中),而且我可以将我的类(很简单)直接扩展到*Spec类中,调用它TestFoo()并实现setId(),但是,正如我之前所说,我担心这根本不是一个解决方案,mock对象是唯一有意义的解决方案
class TestFoo extends Foo
{
    public function setId($id) 
    {
        $this->id = $id
    }
}