Giới thiệu
Được rồi tôi thấy có một giải pháp được cung cấp cho Mockery, vì vậy tôi không thích Mockery, tôi sẽ cung cấp cho bạn một giải pháp thay thế Tiên tri nhưng trước tiên tôi sẽ đề nghị bạn đọc về sự khác biệt giữa Mockery và Tiên tri.
Câu chuyện dài ngắn : "Lời tiên tri sử dụng cách tiếp cận được gọi là ràng buộc thông điệp - điều đó có nghĩa là hành vi của phương thức không thay đổi theo thời gian, mà thay đổi theo phương thức khác."
Mã có vấn đề trong thế giới thực
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;
}
}
Giải pháp tiên tri PhpUnit
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);
}
}
Tóm lược
Một lần nữa, lời tiên tri tuyệt vời hơn! Thủ thuật của tôi là tận dụng tính chất ràng buộc nhắn tin của Tiên tri và mặc dù đáng buồn là nó giống như một mã địa ngục javascript thông thường, gọi lại, bắt đầu bằng $ self = $ this; vì bạn rất hiếm khi phải viết các bài kiểm tra đơn vị như thế này Tôi nghĩ rằng đó là một giải pháp tốt và nó rất dễ thực hiện, gỡ lỗi, vì nó thực sự mô tả việc thực hiện chương trình.
BTW: Có một sự thay thế thứ hai nhưng yêu cầu thay đổi mã chúng tôi đang thử nghiệm. Chúng tôi có thể bao bọc những kẻ gây rối và chuyển chúng sang một lớp riêng:
$chunk->processingInProgress();
$this->chunksStorage->updateChunk($chunk);
có thể được bọc như:
$processorChunkStorage->persistChunkToInProgress($chunk);
và đó là nó nhưng vì tôi không muốn tạo một lớp khác cho nó, tôi thích lớp đầu tiên.