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
}
}