如何使用 Prophesy 在 Zend Expressive 中为 RequestHandlerInterface class 制作测试替身?
How to make a Test Double for the RequestHandlerInterface class in Zend Expressive using Prophesy?
我正在尝试对 Zend Expressive 应用程序中的中间件的 process()
方法进行单元测试。为此,我需要为类型为 RequestHandlerInterface
的方法模拟出 $delegate
参数,并将具有方法 handle()
.
这应该很容易做到,因为我已经在此测试中使用 Prophesy 成功模拟了其他对象:
每当调用 handle()
方法时,我都会收到以下错误:"Unexpected method call on Double\RequestHandlerInterface\P18:\n - handle(\n Double\ServerRequestInterface\P17:000000004a01de0d000000000617c05e Object (\n 'objectProphecy' => Prophecy\Prophecy\ObjectProphecy Object (*Prophecy*)\n )\n )\nexpected calls were:\n - handle(\n\n )"
这是测试。请注意,其他模拟按预期工作,但 $mockDelegate
上的 handle()
方法在调用时仍会抛出错误:
/**
* @test
*/
public function
testReturnsRedirectResponseForHandlerWhenNoErrorsFoundRequestTypePOST()
{
$renderer = $this->prophesize(TemplateRendererInterface::class);
$renderer
->render('app::contract-form-page', [])
->willReturn('');
$validateSubmitAction = new ValidateSubmitAction(
$this->router->reveal(),
$renderer->reveal(),
get_class($this->container->reveal()),
$this->logger->reveal()
);
$mockRequest = $this->prophesize(ServerRequestInterface::class);
$mockRequest->getMethod()->willReturn('POST');
$mockRequest->getBody()->willReturn(
//create fake object with getContents method
new class {
public function getContents(){ return 'location-number=testLoc&contract-number=1234';}
});
$mockDelegate = $this->prophesize(RequestHandlerInterface::class);
$mockDelegate->handle()->willReturn('');
$response = $validateSubmitAction->process(
$mockRequest->reveal(),
$mockDelegate->reveal()
);
$this->assertInstanceOf(ValidateSubmitAction::class, $validateSubmitAction);
}
这是它正在尝试测试的方法。当该方法应该将请求委托给管道时,似乎会发生错误。看这里:
public function process(ServerRequestInterface $request, RequestHandlerInterface $delegate): ResponseInterface
{
...
// Delegate on to the handler
return $delegate->handle($request); //<-- this is where the error occurs in the unit test
如何用Prophesy准确模拟RequestHandlerInterface handle()
方法,从而实现无错测试?
你有这个:$mockDelegate->handle()->willReturn('');
,但它应该是这样的:
$handler->handle(Argument::that([$mockRequest, 'reveal']))->willReturn('');
在您的代码中,您希望调用 handle() 时不带任何参数。但是它是用模拟请求接口的实例调用的。
查看 zend-expressive-session 中的示例:
public function testMiddlewareCreatesLazySessionAndPassesItToDelegateAndPersistsSessionInResponse()
{
$request = $this->prophesize(ServerRequestInterface::class);
$request
->withAttribute(SessionMiddleware::SESSION_ATTRIBUTE, Argument::type(LazySession::class))
->will([$request, 'reveal']);
$response = $this->prophesize(ResponseInterface::class);
$handler = $this->prophesize(RequestHandlerInterface::class);
$handler->handle(Argument::that([$request, 'reveal']))->will([$response, 'reveal']);
$persistence = $this->prophesize(SessionPersistenceInterface::class);
$persistence
->persistSession(
Argument::that(function ($session) use ($persistence, $request) {
$this->assertInstanceOf(LazySession::class, $session);
$this->assertAttributeSame($persistence->reveal(), 'persistence', $session);
$this->assertAttributeSame($request->reveal(), 'request', $session);
return $session;
}),
Argument::that([$response, 'reveal'])
)
->will([$response, 'reveal']);
$middleware = new SessionMiddleware($persistence->reveal());
$this->assertSame($response->reveal(), $middleware->process($request->reveal(), $handler->reveal()));
}
我正在尝试对 Zend Expressive 应用程序中的中间件的 process()
方法进行单元测试。为此,我需要为类型为 RequestHandlerInterface
的方法模拟出 $delegate
参数,并将具有方法 handle()
.
这应该很容易做到,因为我已经在此测试中使用 Prophesy 成功模拟了其他对象:
每当调用 handle()
方法时,我都会收到以下错误:"Unexpected method call on Double\RequestHandlerInterface\P18:\n - handle(\n Double\ServerRequestInterface\P17:000000004a01de0d000000000617c05e Object (\n 'objectProphecy' => Prophecy\Prophecy\ObjectProphecy Object (*Prophecy*)\n )\n )\nexpected calls were:\n - handle(\n\n )"
这是测试。请注意,其他模拟按预期工作,但 $mockDelegate
上的 handle()
方法在调用时仍会抛出错误:
/**
* @test
*/
public function
testReturnsRedirectResponseForHandlerWhenNoErrorsFoundRequestTypePOST()
{
$renderer = $this->prophesize(TemplateRendererInterface::class);
$renderer
->render('app::contract-form-page', [])
->willReturn('');
$validateSubmitAction = new ValidateSubmitAction(
$this->router->reveal(),
$renderer->reveal(),
get_class($this->container->reveal()),
$this->logger->reveal()
);
$mockRequest = $this->prophesize(ServerRequestInterface::class);
$mockRequest->getMethod()->willReturn('POST');
$mockRequest->getBody()->willReturn(
//create fake object with getContents method
new class {
public function getContents(){ return 'location-number=testLoc&contract-number=1234';}
});
$mockDelegate = $this->prophesize(RequestHandlerInterface::class);
$mockDelegate->handle()->willReturn('');
$response = $validateSubmitAction->process(
$mockRequest->reveal(),
$mockDelegate->reveal()
);
$this->assertInstanceOf(ValidateSubmitAction::class, $validateSubmitAction);
}
这是它正在尝试测试的方法。当该方法应该将请求委托给管道时,似乎会发生错误。看这里:
public function process(ServerRequestInterface $request, RequestHandlerInterface $delegate): ResponseInterface
{
...
// Delegate on to the handler
return $delegate->handle($request); //<-- this is where the error occurs in the unit test
如何用Prophesy准确模拟RequestHandlerInterface handle()
方法,从而实现无错测试?
你有这个:$mockDelegate->handle()->willReturn('');
,但它应该是这样的:
$handler->handle(Argument::that([$mockRequest, 'reveal']))->willReturn('');
在您的代码中,您希望调用 handle() 时不带任何参数。但是它是用模拟请求接口的实例调用的。
查看 zend-expressive-session 中的示例:
public function testMiddlewareCreatesLazySessionAndPassesItToDelegateAndPersistsSessionInResponse()
{
$request = $this->prophesize(ServerRequestInterface::class);
$request
->withAttribute(SessionMiddleware::SESSION_ATTRIBUTE, Argument::type(LazySession::class))
->will([$request, 'reveal']);
$response = $this->prophesize(ResponseInterface::class);
$handler = $this->prophesize(RequestHandlerInterface::class);
$handler->handle(Argument::that([$request, 'reveal']))->will([$response, 'reveal']);
$persistence = $this->prophesize(SessionPersistenceInterface::class);
$persistence
->persistSession(
Argument::that(function ($session) use ($persistence, $request) {
$this->assertInstanceOf(LazySession::class, $session);
$this->assertAttributeSame($persistence->reveal(), 'persistence', $session);
$this->assertAttributeSame($request->reveal(), 'request', $session);
return $session;
}),
Argument::that([$response, 'reveal'])
)
->will([$response, 'reveal']);
$middleware = new SessionMiddleware($persistence->reveal());
$this->assertSame($response->reveal(), $middleware->process($request->reveal(), $handler->reveal()));
}