Php 在Lumen中模拟路由控制器中的方法调用以进行测试
在我的Lumen应用程序中,我有以下实现路由控制器的控制器类:Php 在Lumen中模拟路由控制器中的方法调用以进行测试,php,unit-testing,mocking,lumen,mockery,Php,Unit Testing,Mocking,Lumen,Mockery,在我的Lumen应用程序中,我有以下实现路由控制器的控制器类: <?php class MyController { public function route_method(Request $request) { // some code $success = $this->private_method($request->get('get_variable')); // some code retur
<?php
class MyController {
public function route_method(Request $request) {
// some code
$success = $this->private_method($request->get('get_variable'));
// some code
return \response()->json(['results' => $success]);
}
private function private_method($data) {
// some code, calling 3rd party service
return $some_value;
}
}
现在我想编写一个单元测试来确认call/endpoint
返回的响应,返回一个预期的JSON响应,该响应包含'results':true
,但不允许通过模拟后者来路由\u方法()调用私有\u方法(),因为正如在注释中一样,private\u method()
调用第三方服务,我想避免这种情况,所以我想我需要这样的服务:
<?php
class RouteTest extends TestCase {
public function testRouteReturnsExpectedJsonResponse() {
// need to mock the private_method here somehow first, then...
$this->json('GET', '/endpoint', ['get_variable' => 'get_value'])->seeJson(['results' => true]);
}
}
不能模拟此代码的事实是代码设计不好的标志。
我在这里展示的示例只是一个想法,重点是创建一个新类,表示与第三方系统的通信
<?php
namespace App\Http\Controllers;
use App\Services\MyService;
class MyController
{
public function __construct(MyService $service)
{
$this->service = $service;
}
public function route_method(Request $request)
{
// some code
$success = $this->service->some_method($request->get('get_variable'));
// some code
return \response()->json(['results' => $success]);
}
}
基本上,你没有
您应该测试行为,而不是实现。私有方法是一个实现细节
尽管如此,您仍然可以随心所欲,Laravel/Lumen提供了许多选项:
正确的方法:
看看@Felippe Duarte的答案。要使用mocky而不是PHPUnit来添加测试代码,请执行以下操作:
<?php
class RouteTest extends TestCase
{
public function testRouteReturnsExpectedJsonResponse()
{
$someData = 'some_data'; //the data that mock should return
$service = Mockery::mock('App\Services\MyService');
$service->shouldReceive('some_method')->once()->andReturn($someData);
//mock the service instance
$this->app->instance('App\Services\MyService', $service);
// need to mock the private_method here somehow first, then...
$this->json('GET', '/endpoint', ['get_variable' => 'get_value'])->seeJson(['results' => $someData]);
}
}
谢谢!事实上,MyService
类确实存在,但我想我可以在同一个类中模拟private\u方法,而不是MyService
类。但是我从你那里了解到私人的方法不能在这里被嘲笑,对吗?我想这里的重点是责任。控制器没有责任呼叫第三方。但是,你可以在这里得到更多的信息:好吧,我改变了我做测试的方式,不去模仿私有方法,但是仍然有一些不清楚的地方。从您的代码中可以看出,$this->app->instance()
调用将模拟对象设置为响应some\u方法
调用,但我的情况仍然不是这样。当触发$this-json()
调用时,模拟对象不是处理some\u方法调用的对象。
<?
namespace App\Services;
class MyService
{
public function some_method($variable)
{
//do something
}
}
<?php
class RouteTest extends TestCase {
public function testRouteReturnsExpectedJsonResponse() {
$service = $this->getMockBuilder('App\Services\MyService')
->disableOriginalConstructor()
->getMock();
$somedata = 'some_data' //the data that mock should return
$service->expects($this->any())
->method('some_method')
->willReturn($somedata);
//mock the service instance
$this->app->instance('App\Services\MyService', $service);
// need to mock the private_method here somehow first, then...
$this->json('GET', '/endpoint', ['get_variable' => 'get_value'])->seeJson(['results' => true]);
}
}
<?php
class RouteTest extends TestCase
{
public function testRouteReturnsExpectedJsonResponse()
{
$someData = 'some_data'; //the data that mock should return
$service = Mockery::mock('App\Services\MyService');
$service->shouldReceive('some_method')->once()->andReturn($someData);
//mock the service instance
$this->app->instance('App\Services\MyService', $service);
// need to mock the private_method here somehow first, then...
$this->json('GET', '/endpoint', ['get_variable' => 'get_value'])->seeJson(['results' => $someData]);
}
}
<?php
class MyController {
public function route_method(Request $request) {
// some code
$success = $this->private_method($request->get('get_variable'));
// some code
return \response()->json(['results' => $success]);
}
private function private_method($data) {
// say third party is some paypal class
$thirdParty = app(Paypal::class);
return $thirdParty->makePayment($data);
}
}
<?php
class RouteTest extends TestCase
{
public function testRouteReturnsExpectedJsonResponse()
{
$someData = 'some_data'; //the data that mock should return
$paypalMock = Mockery::mock(Paypal::class);
$paypalMock->shouldReceive('makePayment')->once()->with('get_value')->andReturn($someData);
//mock the service instance
$this->app->instance(Paypal::class, $paypalMock);
// need to mock the private_method here somehow first, then...
$this->json('GET', '/endpoint', ['get_variable' => 'get_value'])->seeJson(['results' => $someData]);
}
}