Hướng dẫn phpunit mock method with different arguments - phpunit mock method với các đối số khác nhau

Giới thiệu

Được rồi, tôi thấy có một giải pháp được cung cấp cho sự nhạo báng, vì vậy tôi không thích sự nhạo báng, tôi sẽ cung cấp cho bạn một sự thay thế tiên tri nhưng tôi sẽ đề nghị bạn trước tiên đọc về sự khác biệt giữa sự nhạo báng và lời tiên tri trước.

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 tin nhắn - điều đó có nghĩa là hành vi của phương pháp không thay đổi theo thời gian, mà được thay đổi bởi phương pháp khác.": "Prophecy uses approach called message binding - it means that behaviour of the method does not change over time, but rather is changed by the other method."

Mã có vấn đề trong thế giới thực để bao gồm

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

Bản tóm tắt

Một lần nữa, lời tiên tri là tuyệt vời hơn! Thủ thuật của tôi là tận dụng bản chất ràng buộc nhắn tin của lời tiên tri và mặc dù nó đáng buồn trông giống như một mã địa ngục JavaScript điển hình, gọi lại, bắt đầu với $ self = $ này; 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 đẹp và nó chắc chắn dễ theo dõi, gỡ lỗi, vì nó thực sự mô tả việc thực hiện chương trình.$self = $this; as you very rarely have to write unit tests like this I think it's a nice solution and it's definitely easy to follow, debug, as it actually describes the program execution.

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ể bọc các kẻ gây rối và chuyển chúng đến một lớp riêng biệt:

$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.

Chủ Đề