我想对我的服务类进行单元测试,这样可以节省2个实体。 只有测试失败,因为person实体没有从entityManager获取ID,因为它是模拟的。
有没有办法在第一次调用flush后更新person对象。
class Foo
{
...
public function save()
{
$em = $this->getEntityManager();
$person = new Person();
$person->setName('Dude');
$em->persist($person);
$em->flush();
$user = new User();
$user->setPersonId($person->getId());
$user->setEmail('dude@example.com');
$em->persist($user);
$em->flush();
}
}
class FooTest
{
...
public function testSave_UserIsSaved()
{
$person = new Person();
$person->setName('dude');
$user = new User();
$user->setPersonId(4); // <-- this is where it gets wrong
$user->setEmail('dude@example.com');
$person = array(
'name' => 'Dude',
);
$user = array(
'person_id' => 3,
'email' => 'dude@example.com',
);
$emMock = $this->getMockBuilder('\Doctrine\ORM\EntityManager')
->setMethods(array('persist', 'flush'))
->getMock();
$emMock->expects($this->exactly(2))
->method('persist')
->with(
$this->logicalOr(
$this->equalTo($person),
$this->equalTo($user)
)
);
$emMock->expects($this->exactly(2))
->method('flush');
$foo = new Foo($emMock);
$foo->save();
}
}
答案 0 :(得分:3)
您可以使用returnCallback
函数处理传递的对象(Some example here)。
实际上你可以告诉persist mocked方法在对象上做一些东西,例如,一个基于你的例子的工作解决方案:
class FooTest extends \PHPUnit_Framework_TestCase {
public function testSave_UserIsSaved()
{
$person = new Person();
$person->setName('Dude');
$user = new User();
$user->setPersonId(4); // <-- this is where it gets wrong
$user->setEmail('dude@example.com');
$emMock = $this->getMockBuilder('\Doctrine\ORM\EntityManager')
->setMethods(array('persist', 'flush'))
->disableOriginalConstructor()
->getMock()
;
$emMock->expects($this->exactly(2))
->method('persist')
->with(
$this->logicalOr(
$this->equalTo($person),
$this->equalTo($user)
)
)
->will($this->returnCallback(function($o) {
if ($o instanceof \Acme\DemoBundle\Model\Person){
$o->setId(4);
}
}));
$emMock->expects($this->exactly(2))
->method('flush');
$foo = new Foo($emMock);
$foo->save();
}
使用PHPUnit 4.3.5进行测试,有关提示,请检查this SO Question
希望这个帮助
答案 1 :(得分:1)
有几点,主要问题首先是:如果您正在测试类Foo
,那么所有其他复杂的依赖项应该是mocked,因为这样可以让您单独测试单元,因此&#39; unit&# 39;测试
如果您创建工厂类以从参数创建Person
,并将其作为依赖项传递到主应用程序中的类Foo
,那么在您的测试套件中,您可以传入模拟这个工厂将为您提供一个Person
预先初始化的ID。更好的是,如果你想避免在被刷新之前Person
已经拥有Id这一事实的错误测试结果,那么使模拟工厂返回模拟Person
。然后,您可以使用回调来存储模拟的getId方法,该回调仅在调用EntityManager
的flush方法的模拟时返回非null。
除此之外,我建议您稍微更改模型:如果Person
始终需要User
,则需要将其作为构造函数的类型提示参数,以及任何其他最初需要的依赖项。这样,您可以使用association mapping或直接通过ID抽象User
和Person
之间的关系,但您的Foo
班级不需要知道这