代码之家  ›  专栏  ›  技术社区  ›  Kiren S

如何确定PHPUnit模拟失败的原因?

  •  1
  • Kiren S  · 技术社区  · 6 年前

    我想下课进行单元测试。

    <?php
    namespace Gpx\Handlers;
    use Gpx\EntityInfrastructure\Model\Events\SessionInvalidated;
    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\HfxProjectionHelper;
    use Gpx\HfxEventSourcing\HfxEventMetadata;
    use Gpx\HfxEventSourcing\HfxRepository;
    use Gpx\Hfx\MessageTransport\Response\SendableResponse;
    
    class BroadcastSessionInvalidated implements SynchronousHandlerInterface
    {
    
        /** @var HfxRepository  */
        private $repository;
    
        /** @var  HfxProjectionHelper */
        private $projectionHelper;
    
    
        public function __construct(HfxRepository $repository, HfxProjectionHelper $projectionHelper)
        {
            $this->repository = $repository;
            $this->projectionHelper = $projectionHelper;
        }
    
    
        public function handleSynchronousMessage(MessageHandlingContextInterface $context): SendableResponse
        {
            $content = $context->message();
            $header = $context->rawMessage()->header();
    
            $metadata = HfxEventMetadata::fromHfxHeader($header);
            $payload = Payload::fromMessageContent($content);
    
            /** @var HfxAggregateRoot $roleAggregate */
            // Gpx\HfxEventSourcing\HfxAggregateRoot
            $roleAggregate = $this->repository->get($payload->id());
            $roleAggregate->registerEvent(SessionInvalidated::class, $payload, $metadata);
    
            $this->repository->save($roleAggregate);
            $currentEvent = $roleAggregate->currentEvent();
            $context->sendNonBlockingAsynchronous('session_invalidated',$content);
    
            $this->projectionHelper->updateReadModel();
            return SendableResponse::answerTo($context->rawMessage(), 1100, [
                'responseMessage' => 'Success',
                'event' => $currentEvent
            ]);
        }
    }
    

    到目前为止,我已经编写了测试用例

    <?php
    
    namespace Gpx\Tests\Feature;
    
    use Ramsey\Uuid\Uuid;
    use Gpx\Json\JsonEncode;
    use Prophecy\Argument;
    use PHPUnit\Framework\TestCase;
    use Gpx\HfxEventSourcing\Hfx;
    use Gpx\HfxEventSourcing\HfxRepository;
    use Gpx\Hfx\Framework\MessageTransportApplication\Handler\MessageHandlingContextInterface;
    use Gpx\Handlers\BroadcastSessionInvalidated;
    use Gpx\Hfx\MessageTransport\Message\ReceivedMessage;
    use Prooph\EventSourcing\AggregateRoot;
    use Gpx\HfxEventSourcing\HfxAggregateRoot;
    
    
    class BroadcastSessionInvalidatedTest extends TestCase
    {
        /** @var HfxRepository */
        private $repository;
    
        /** @var  Hfx */
        private $projectionHelper;
    
        // We have to test handleSynchronousMessage handler whether it is returning sendable response with certain properties in it.
        public function testHandleSynchronousMessage()
        {
    
            // Expected return value of message() function of $context
            $expectedReturnValue = [
                "session_id" => "1a92-4376-a8eb-deaf208e1",
                "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 $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' => "8365526e-fb92-4376-a8eb-deaf208edf61",
                    'title' => "A task's title."
                ]
            ];
    
            // Prophecy means prediction of the future object
    
            // Prediction of $context object starts
            $context = $this->prophesize(MessageHandlingContextInterface::class);
            $context->message(Argument::any())->willReturn($expectedReturnValue);
    
            $encodedMessage = new JsonEncode($headerResponseExpected);
            $rawMessage = ReceivedMessage::fromEncodedMessage($encodedMessage->asString());
            $context->rawMessage()->willReturn($rawMessage);
    
            $context->sendNonBlockingAsynchronous('platform_session_initiated', Argument::type("array"))
                ->shouldBeCalled();
            // Prediction of $context object ends
    
            // Repository Mocking Starts
            $ravenAggregateRoot = $this->getMockBuilder(HfxAggregateRoot::class)
                ->disableOriginalConstructor()
                ->getMock();
    
            $this->ravenRepository = $this->prophesize(HfxRepository::class);
            $this->ravenRepository->get('1a92-4376-a8eb-deaf208e1')->shouldBeCalled()->willReturn($ravenAggregateRoot);
            $this->ravenRepository->save(Argument::any())->shouldBeCalled();
            // Repository Mocking Ends
    
            // Mocking Hfx and calling the method updateReadModel which will return the string UpdateReadModel
            $this->projectionHelper = $this->createMock(Hfx::class);
            $this->projectionHelper->method('updateReadModel')
                ->willReturn('UpdateReadModel');
    
            // Actual calling
            $broadcastPlatformSessionInvalidated = new BroadcastSessionInvalidated($this->ravenRepository->reveal(), $this->projectionHelper);
            //$broadcastPlatformSessionInvalidated = new BroadcastSessionInvalidated($this->ravenRepository, $this->projectionHelper);
            $response = $broadcastPlatformSessionInvalidated->handleSynchronousMessage($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']);
    
    
        }
    }
    

    当我执行测试时,它会抛出一个错误

    PHPUnit 6.5.4 by Sebastian Bergmann and contributors.
    .E                                                                  2 / 2 (100%)
    Time: 506 ms, Memory: 6.00MB
    There was 1 error:
    1) Gpx\Tests\Feature\BroadcastSessionInvalidatedTest::testHandleSynchronousMessage
    Prophecy\Exception\Call\UnexpectedCallException: Method call:
      - sendNonBlockingAsynchronous("session_invalidated", ["session_id" => "1a92-4376-a8eb-deaf208e1", "user_id" => "we", "access_jwt" => "C", "access_token" => "john@gmail.com", "refresh_token" => "C", "refresh_token_expires" => "john@gmail.com"])
    on Double\MessageHandlingContextInterface\P3 was not expected, expected calls were:
      - message(*)
      - rawMessage()
      - sendNonBlockingAsynchronous(exact("platform_session_initiated"), type(array))
    /vagrant/services/sessions-stream/app/src/Gpx/Handlers/BroadcastSessionInvalidated.php:54
    /vagrant/services/sessions-stream/app/tests/Feature/BroadcastPlatformSessionInvalidatedTest.php:107
    ERRORS!
    Tests: 2, Assertions: 6, Errors: 1.
    

    我做错了什么?

    1 回复  |  直到 6 年前
        1
  •  1
  •   ishegg    6 年前

    异常告诉您出了什么问题:您使用 shouldBeCalled() 告诉PHPUnit检查方法 sendNonBlockingAsynchronous() 使用第一个参数调用 platform_session_initiated array 在第二个参数中。

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

    满足第二个条件,但在实际方法中,第一个参数是 session_invalidated :

    // BroadcastSessionInvalidated
    $context->sendNonBlockingAsynchronous('session_invalidated',$content);
    

    因此,将期望更改为

    // BroadcastSessionInvalidatedTest
    $context->sendNonBlockingAsynchronous('session_invalidated', Argument::type("array"))
            ->shouldBeCalled();
    

    它会起作用的。