Intro
Ok je vois qu'il y a une solution fournie pour Mockery, donc comme je n'aime pas Mockery, je vais vous donner une alternative Prophecy mais je vous suggère d'abord de lisez d'abord la différence entre la moquerie et la prophétie.
Pour faire court : "La prophétie utilise une approche appelée liaison de messages - cela signifie que le comportement de la méthode ne change pas avec le temps, mais qu'il est plutôt modifié par l'autre méthode".
Code problématique du monde réel à couvrir
class Processor
{
/**
* @var MutatorResolver
*/
private $mutatorResolver;
/**
* @var ChunksStorage
*/
private $chunksStorage;
/**
* @param MutatorResolver $mutatorResolver
* @param ChunksStorage $chunksStorage
*/
public function __construct(MutatorResolver $mutatorResolver, ChunksStorage $chunksStorage)
{
$this->mutatorResolver = $mutatorResolver;
$this->chunksStorage = $chunksStorage;
}
/**
* @param Chunk $chunk
*
* @return bool
*/
public function process(Chunk $chunk): bool
{
$mutator = $this->mutatorResolver->resolve($chunk);
try {
$chunk->processingInProgress();
$this->chunksStorage->updateChunk($chunk);
$mutator->mutate($chunk);
$chunk->processingAccepted();
$this->chunksStorage->updateChunk($chunk);
}
catch (UnableToMutateChunkException $exception) {
$chunk->processingRejected();
$this->chunksStorage->updateChunk($chunk);
// Log the exception, maybe together with Chunk insert them into PostProcessing Queue
}
return false;
}
}
Solution PhpUnit Prophecy
class ProcessorTest extends ChunkTestCase
{
/**
* @var Processor
*/
private $processor;
/**
* @var MutatorResolver|ObjectProphecy
*/
private $mutatorResolverProphecy;
/**
* @var ChunksStorage|ObjectProphecy
*/
private $chunkStorage;
public function setUp()
{
$this->mutatorResolverProphecy = $this->prophesize(MutatorResolver::class);
$this->chunkStorage = $this->prophesize(ChunksStorage::class);
$this->processor = new Processor(
$this->mutatorResolverProphecy->reveal(),
$this->chunkStorage->reveal()
);
}
public function testProcessShouldPersistChunkInCorrectStatusBeforeAndAfterTheMutateOperation()
{
$self = $this;
// Chunk is always passed with ACK_BY_QUEUE status to process()
$chunk = $this->createChunk();
$chunk->ackByQueue();
$campaignMutatorMock = $self->prophesize(CampaignMutator::class);
$campaignMutatorMock
->mutate($chunk)
->shouldBeCalled();
$this->mutatorResolverProphecy
->resolve($chunk)
->shouldBeCalled()
->willReturn($campaignMutatorMock->reveal());
$this->chunkStorage
->updateChunk($chunk)
->shouldBeCalled()
->will(
function($args) use ($self) {
$chunk = $args[0];
$self->assertTrue($chunk->status() === Chunk::STATUS_PROCESSING_IN_PROGRESS);
$self->chunkStorage
->updateChunk($chunk)
->shouldBeCalled()
->will(
function($args) use ($self) {
$chunk = $args[0];
$self->assertTrue($chunk->status() === Chunk::STATUS_PROCESSING_UPLOAD_ACCEPTED);
return true;
}
);
return true;
}
);
$this->processor->process($chunk);
}
}
Résumé
Encore une fois, Prophecy est encore plus génial ! Mon astuce consiste à tirer parti de la nature de la liaison par messagerie de Prophecy et, même si cela ressemble tristement à un code typique de l'enfer de callback javascript, commencer par $self = $this ; Comme il est très rare d'avoir à écrire des tests unitaires de ce type, je pense que c'est une bonne solution et qu'elle est vraiment facile à suivre et à déboguer, car elle décrit réellement l'exécution du programme.
BTW : Il existe une deuxième alternative mais elle nécessite de modifier le code que nous testons. Nous pourrions envelopper les fauteurs de trouble et les déplacer dans une classe distincte :
$chunk->processingInProgress();
$this->chunksStorage->updateChunk($chunk);
pourrait être emballé comme :
$processorChunkStorage->persistChunkToInProgress($chunk);
et c'est tout mais comme je ne voulais pas créer une autre classe pour cela, je préfère la première.
0 votes
En plus de la réponse ci-dessous, vous pouvez également utiliser la méthode de cette réponse : stackoverflow.com/questions/5484602/
0 votes
J'aime cette réponse stackoverflow.com/a/10964562/614709