【问题标题】:PHP unit failure testingPHP单元故障测试
【发布时间】:2018-02-28 22:46:54
【问题描述】:

我必须测试这个类的失败情况

<?php
namespace Gpx\Handlers;
use Gpx\EntityInfrastructure\Model\Events\PlatformSessionInitiated;
use Gpx\EntityInfrastructure\Model\Payload;
use Gpx\Hfx\Framework\MessageTransportApplication\Handler\SynchronousHandlerInterface;
use Gpx\Hfx\Framework\MessageTransportApplication\Handler\MessageHandlingContextInterface;
use Gpx\HfxEventSourcing\HfxAggregateRoot;
use Gpx\HfxEventSourcing\HfxEventMetadata;
use Gpx\HfxEventSourcing\HfxProjectionHelper;
use Gpx\HfxEventSourcing\HfxRepository;
use Gpx\Hfx\MessageTransport\Response\SendableResponse;
use Gpx\Exceptions\IdNotDefinedException;
use Gpx\Exceptions\AggregateNotFoundException;

class BroadcastPlatformSessionInitiated implements SynchronousHandlerInterface
{

    /** @var HfxRepository */
    private $repository;

    /** @var  HfxProjectionHelper */
    private $projectionHelper;


    public function __construct(HfxRepository $repository, HfxProjectionHelper $projectionHelper)
    {
        $this->repository = $repository;
        $this->projectionHelper = $projectionHelper;
    }

    /*
     * @param MessageHandlingContextInterface $context
     * @return SendableResponse
     */
    public function handleSynchronousMessage(MessageHandlingContextInterface $context): SendableResponse
    {
        try {
            $content = $context->message();
            $header = $context->rawMessage()->header();

            $metadata = HfxEventMetadata::fromHfxHeader($header);
            $payload = Payload::fromMessageContent($content);

            $roleAggregate = HfxAggregateRoot::createEntityFromEvent(PlatformSessionInitiated::class, $payload, $metadata);
            $this->repository->save($roleAggregate);

            $currentEvent = $roleAggregate->currentEvent();
            $context->sendNonBlockingAsynchronous('platform_session_initiated', $currentEvent);

            $this->projectionHelper->updateReadModel(HfxAggregateRoot::class);

            return SendableResponse::answerTo($context->rawMessage(), 1000, [
                'responseMessage' => 'Success',
                'event' => $currentEvent
            ]);
        } catch (IdNotDefinedException $e) {
            return SendableResponse::answerTo($context->rawMessage(), 2000, [
                'responseMessage' => 'Failure. Session Id is not defined.'
            ]);
        }
    }
}

下面是我写的测试用例

<?php

namespace Gpx\Tests\Handlers;

use Ramsey\Uuid\Uuid;
use Gpx\Json\JsonEncode;
use Prophecy\Argument;
use PHPUnit\Framework\TestCase;
use Gpx\HfxEventSourcing\HfxProjectionHelper;
use Gpx\HfxEventSourcing\HfxRepository;
use Gpx\Hfx\Framework\MessageTransportApplication\Handler\MessageHandlingContextInterface;
use Gpx\Handlers\BroadcastPlatformSessionInitiated;
use Gpx\Hfx\MessageTransport\Message\ReceivedMessage;
use Gpx\Exceptions\IdNotDefinedException;

class BroadcastPlatformSessionInitiatedTest extends TestCase
{
    /** @var HfxRepository */
    private $repository;

    /** @var  HfxProjectionHelper */
    private $projectionHelper;

    /** @var  MessageHandlingContext */
    private $context;

    /**
     * This will run before each test
     */
    public function setUp()
    {

        // Expected return value of message() function of $this->context
        $expectedReturnValue = [
            "session_id" => "1a92-4376-a8eb-deaf208ssess11",
            "user_id" => "we",
            "access_jwt" => "C",
            "access_token" => "john@gmail.com",
            "refresh_token" => "C",
            "refresh_token_expires" => "john@gmail.com"
        ];

        // Expected return value of rawMessage() function of $this->context
        $headerResponseExpected = [
            'header' => [
                'version' => '2.0',
                'originId' => (string)Uuid::uuid4(),
                'destination' => 'application/meta@1.0.0',
                'sent' => '2017-12-19T10:12:37.941+00:00'
            ],
            'content' => [
                'session_id' => null,
                'title' => "A task's title."
            ]
        ];

        // Prediction of $this->context object starts
        $this->context = $this->prophesize(MessageHandlingContextInterface::class);
        $this->context->message(Argument::any())->willReturn($expectedReturnValue);

        $encodedMessage = new JsonEncode($headerResponseExpected);
        $rawMessage = ReceivedMessage::fromEncodedMessage($encodedMessage->asString());
        $this->context->rawMessage()->willReturn($rawMessage);

        $this->context->sendNonBlockingAsynchronous('platform_session_initiated', Argument::type("array"))
            ->shouldBeCalled();
        // Prediction of $this->context object ends
    }

    // We have to test handleSynchronousMessage handler whether it is returning sendable response with certain properties in it.
    public function testHandleSynchronousMessageForSuccess()
    {

        // Prophecy means prediction of the future object
        $this->ravenRepository = $this->prophesize(HfxRepository::class);
        $this->ravenRepository->save(Argument::any())
            ->shouldBeCalled();

        // Mocking HfxProjectionHelper and calling the method updateReadModel which will return the string UpdateReadModel
        $this->projectionHelper = $this->createMock(HfxProjectionHelper::class);
        $this->projectionHelper->method('updateReadModel')
            ->willReturn('UpdateReadModel');

        // Actual calling
        $broadcastPlatformSessionInitiated = new BroadcastPlatformSessionInitiated($this->ravenRepository->reveal(), $this->projectionHelper);
        $response = $broadcastPlatformSessionInitiated->handleSynchronousMessage($this->context->reveal());

        $this->assertInstanceOf('Gpx\Hfx\MessageTransport\Response\SendableResponse', $response);
        $this->assertArrayHasKey("responseMessage", $response->content()->data());
        $this->assertArrayHasKey("event", $response->content()->data());
        $this->assertEquals("Success", $response->content()->data()['responseMessage']);

    }

    // We have to test handleSynchronousMessage handler whether it is returning sendable response with certain properties in it.
    public function testHandleSynchronousMessageForFailure()
    {

        // Expected return value of message() function of $this->context
        $expectedReturnValue = [
            "session_id" => null,
            "user_id" => "we",
            "access_jwt" => "C",
            "access_token" => "john@gmail.com",
            "refresh_token" => "C",
            "refresh_token_expires" => "john@gmail.com"
        ];

        // Expected return value of rawMessage() function of $this->context
        $headerResponseExpected = [
            'header' => [
                'version' => '2.0',
                'originId' => (string)Uuid::uuid4(),
                'destination' => 'application/meta@1.0.0',
                'sent' => '2017-12-19T10:12:37.941+00:00'
            ],
            'content' => [
                'session_id' => '1a92-4376-a8eb-deaf208ssess11',
                'title' => "A task's title."
            ]
        ];

        // Prediction of $this->context object starts
        $this->context = $this->prophesize(MessageHandlingContextInterface::class);
        $this->context->message(Argument::any())->willReturn($expectedReturnValue);

        $encodedMessage = new JsonEncode($headerResponseExpected);
        $rawMessage = ReceivedMessage::fromEncodedMessage($encodedMessage->asString());
        $this->context->rawMessage()->willReturn($rawMessage);

        $this->context->sendNonBlockingAsynchronous('platform_session_initiated', Argument::type("array"))->shouldNotBeCalled();
        // Prediction of $this->context object ends

        // Prophecy means prediction of the future object
        $this->ravenRepository = $this->prophesize(HfxRepository::class);


        // Mocking HfxProjectionHelper and calling the method updateReadModel which will return the string UpdateReadModel
        $this->projectionHelper = $this->createMock(HfxProjectionHelper::class);
        $this->projectionHelper->method('updateReadModel')->willReturn('UpdateReadModel');

        // Actual calling
        $broadcastPlatformSessionInitiated = new BroadcastPlatformSessionInitiated($this->ravenRepository->reveal(), $this->projectionHelper);
        $response = $broadcastPlatformSessionInitiated->handleSynchronousMessage($this->context->reveal());

        $this->assertInstanceOf('Gpx\Hfx\MessageTransport\Response\SendableResponse', $response);
        $this->assertArrayHasKey("responseMessage", $response->content()->data());
        $this->assertEquals("Failure. Session Id is not defined.", $response->content()->data()['responseMessage']);

    }
}

这是我为 testHandleSynchronousMessageForFailure 遇到的失败

Gpx\Tests\Handlers\BroadcastPlatformSessionInitiatedTest::testHandleSynchronousMessageForFailure
Some predictions failed:
  Double\MessageHandlingContextInterface\P3:
    No calls have been made that match:
      Double\MessageHandlingContextInterface\P3->sendNonBlockingAsynchronous(exact("platform_session_initiated"), type(array))
    but expected at least one.

FAILURES!
Tests: 3, Assertions: 18, Failures: 1.

谁能澄清我在这里做错了什么?

【问题讨论】:

    标签: php unit-testing phpunit prophecy


    【解决方案1】:

    您的setUp() 方法在每个 测试之前被调用,所以testHandleSynchronousMessageForFailure() 也期望sendNonBlockingAsynchronous() 被调用:

    $this->context->sendNonBlockingAsynchronous('platform_session_initiated', Argument::type("array"))
            ->shouldBeCalled();
    

    即使你在失败测试中调用shouldNotBeCalled()。因此,将shouldBeCalled() 调用移动到testHandleSynchronousMessageForSuccess(),这样它将期望它在成功测试中被调用,而 在失败测试中被调用。

    您还应该告诉 PHPUnit 在失败测试中期待 IdNotDefinedException

    $this->expectException(Gpx\Exceptions\IdNotDefinedException::class);
    

    【讨论】:

    • 是的,我更正了。现在测试通过了。但我没有使用 expectException 方法。我做错什么了吗?
    • 太棒了!是的,没有必要,但为了完整起见,如果可以添加。
    • 将添加它。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-05
    • 2017-02-16
    • 2013-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多