Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/266.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 在Lumen中模拟路由控制器中的方法调用以进行测试_Php_Unit Testing_Mocking_Lumen_Mockery - Fatal编程技术网

Php 在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

在我的Lumen应用程序中,我有以下实现路由控制器的控制器类:

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