Disons qu'il existe une telle fonction :
function a()
{
$entity = $this->getEntity();
$entity->setSomePrivateVar();
$service = $this->getService();
$service->doSomething($entity);
}
Je veux tester que
$service->doSomething($entity);
est appelé avec la bonne $entité.
L'entité $ appelle setSomePrivateVar()
Dans un code d'application réel, j'ai fait quelque chose comme ça :
Obtenez une copie de l'entité et testez que setSomePrivateVar est appelé.
Obtenez un objet fantaisie de $service et testez que doSomething() est appelé avec le paramètre $entity.
Ça a l'air bien.
Mais le problème est que si je remanie le code et appelle d'abord doSomething() sur le service et ensuite setSomePrivateVar() sur $entity, le test passe toujours.
Mais la fonction est maintenant fausse, car doSomething dépend du champ privé de $entity qui est défini par setSomePrivateVar().
Par exemple, je le remanierais comme suit :
function a()
{
$entity = $this->getEntity();
$service = $this->getService();
$service->doSomething($entity);
// this line moved
$entity->setSomePrivateVar();
}
Il semble donc que PhpUnit ne vérifie pas les champs privés de $entity. Si c'était par exemple un tableau, alors la fonction with() verrait que le tableau passé n'est pas le même que celui attendu.
Alors comment puis-je tester que doSomething() obtient $entity dans un état correct (que setSomePrivateVar() a été appelé sur l'entité avant de la passer à doSomething()) ?
Peut-être que ça a quelque chose à voir avec le fait que $entity soit moqué.
Mise à jour avec un exemple concret
public function setNotifyUsers(AnnualConsolidation $consolidation, $status)
{
$consolidation->setNotifyUsers($status); // if move this method after the flush(), tesst does not fail
$this->entityManager->persist($consolidation);
$this->entityManager->flush();
}
public function testNotifyUsers()
{
$consolidation = $this->getMockBuilder(AnnualConsolidation::class)
->setMethods(['setNotifyUsers'])
->getMock();
$consolidation
->expects($this->once())
->method('setNotifyUsers')
;
$this->entityManager
->expects($this->at(0))
->method('persist')
->with($consolidation)
;
$this->entityManager
->expects($this->at(1))
->method('flush')
;
/** @var AnnualConsolidation $consolidation */
$this->consolidationsService->setNotifyUsers($consolidation, true);
}
Nous discutions de la pertinence de tester la méthode setNotifyUsers de cette manière. J'essayais de tester sans toucher à la base de données. L'un d'entre eux pense qu'il pourrait être nécessaire de tester avec la base de données, car si l'on remanie la méthode sans changer la logique, le test pourrait être nécessaire pour la remanier. D'un autre côté, il est peu probable que cette méthode soit remaniée à ce point.
Mais il existe peut-être aussi un moyen de simplement tester que flush() est appelé après persist() sans en informer les index, car dans d'autres exemples, les index pourraient devoir être mis à jour après l'ajout d'un appel avant persist et cela pourrait représenter trop de travail pour que les tests fonctionnent.
Mais pour ce sujet - je veux d'abord savoir comment faire échouer le test - si je déplace setNotifyUsers après le flush(). Le test n'échoue pas. Alors que si nous faisions un test avec la base de données de frappe - nous verrions que le statut de $consolidation n'est pas mis à jour.
Un type m'a dit de vérifier, d'affirmer ce qui est passé à la méthode persist. Je n'ai pas encore essayé, mais je ne suis pas sûr que cela soit possible sur une $consolidation fantaisie. Est-ce que le mocked $consolidation a un état comme le vrai $consolidation aurait ?