pbootcms网站模板|日韩1区2区|织梦模板||网站源码|日韩1区2区|jquery建站特效-html5模板网

在 Laravel 測試用例中模擬一個 http 請求并解析路

Simulate a http request and parse route parameters in Laravel testcase(在 Laravel 測試用例中模擬一個 http 請求并解析路由參數)
本文介紹了在 Laravel 測試用例中模擬一個 http 請求并解析路由參數的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!

問題描述

我正在嘗試創(chuàng)建單元測試來測試一些特定的類.我使用 app()->make() 來實例化要測試的類.所以實際上,不需要 HTTP 請求.

I'm trying to create unit tests to test some specific classes. I use app()->make() to instantiate the classes to test. So actually, no HTTP requests are needed.

然而,一些被測試的函數需要來自路由參數的信息,以便他們進行調用,例如request()->route()->parameter('info'),這會拋出異常:

However, some of the tested functions need information from the routing parameters so they'll make calls e.g. request()->route()->parameter('info'), and this throws an exception:

在 null 上調用成員函數 parameter().

Call to a member function parameter() on null.

我玩了很多,嘗試過類似的東西:

I've played around a lot and tried something like:

request()->attributes = new SymfonyComponentHttpFoundationParameterBag(['info' => 5]);  

request()->route(['info' => 5]);  

request()->initialize([], [], ['info' => 5], [], [], [], null);

但他們都沒有工作......

but none of them worked...

我如何手動初始化路由器并向其提供一些路由參數?或者干脆讓 request()->route()->parameter() 可用?

How could I manually initialize the router and feed some routing parameters to it? Or simply make request()->route()->parameter() available?

@Loek:你沒有理解我.基本上,我正在做:

@Loek: You didn't understand me. Basically, I'm doing:

class SomeTest extends TestCase
{
    public function test_info()
    {
        $info = request()->route()->parameter('info');
        $this->assertEquals($info, 'hello_world');
    }
}

沒有請求"涉及.request()->route()->parameter() 調用實際上位于我真實代碼中的一個服務提供者中.此測試用例專門用于測試該服務提供者.沒有一個路由可以打印該提供程序中方法的返回值.

No "requests" involved. The request()->route()->parameter() call is actually located in a service provider in my real code. This test case is specifically used to test that service provider. There isn't a route which will print the returning value from the methods in that provider.

推薦答案

我假設您需要模擬一個請求,而不是實際調度它.模擬請求到位后,您希望探測它的參數值并開發(fā)您的測試用例.

I assume you need to simulate a request without actually dispatching it. With a simulated request in place, you want to probe it for parameter values and develop your testcase.

有一種未公開的方法可以做到這一點.你會大吃一驚!

There's an undocumented way to do this. You'll be surprised!

眾所周知,Laravel 的 IlluminateHttpRequest 類基于 SymfonyComponentHttpFoundationRequest.上游類不允許您以 setRequestUri() 方式手動設置請求 URI.它根據實際的請求標頭計算出來.別無他法.

As you already know, Laravel's IlluminateHttpRequest class builds upon SymfonyComponentHttpFoundationRequest. The upstream class does not allow you to setup a request URI manually in a setRequestUri() way. It figures it out based on the actual request headers. No other way around.

好的,閑聊就夠了.讓我們嘗試模擬一個請求:

OK, enough with the chatter. Let's try to simulate a request:

<?php

use IlluminateHttpRequest;

class ExampleTest extends TestCase
{
    public function testBasicExample()
    {
        $request = new Request([], [], ['info' => 5]);

        dd($request->route()->parameter('info'));
    }
}

正如你自己提到的,你會得到一個:

As you mentioned yourself, you'll get a:

錯誤:在 null 上調用成員函數 parameter()

Error: Call to a member function parameter() on null

我們需要一個Route

這是為什么?為什么 route() 返回 null?

看看它的實現 以及它的伴隨方法的實現;getRouteResolver().getRouteResolver() 方法返回一個空閉包,然后 route() 調用它,因此 $route 變量將為 null.然后它被返回,因此......錯誤.

Have a look at its implementation as well as the implementation of its companion method; getRouteResolver(). The getRouteResolver() method returns an empty closure, then route() calls it and so the $route variable will be null. Then it gets returned and thus... the error.

在真實的 HTTP 請求上下文中,Laravel設置它的路由解析器,這樣你就不會得到這樣的錯誤.現在您正在模擬請求,您需要自己進行設置.讓我們看看如何.

In a real HTTP request context, Laravel sets up its route resolver, so you won't get such errors. Now that you're simulating the request, you need to set up that by yourself. Let's see how.

<?php

use IlluminateHttpRequest;
use IlluminateRoutingRoute;

class ExampleTest extends TestCase
{
    public function testBasicExample()
    {
        $request = new Request([], [], ['info' => 5]);

        $request->setRouteResolver(function () use ($request) {
            return (new Route('GET', 'testing/{info}', []))->bind($request);
        });

        dd($request->route()->parameter('info'));
    }
}

查看從 Route 的另一個示例" rel="noreferrer">Laravel 自己的RouteCollection 類.

See another example of creating Routes from Laravel's own RouteCollection class.

所以,現在你不會得到那個錯誤,因為你實際上有一個綁定了請求對象的路由.但它還不會起作用.如果我們此時運行 phpunit,我們會得到一個 null !如果你執(zhí)行一個 dd($request->route()) 你會看到即使它設置了 info 參數名稱,它的 parameters 數組為空:

So, now you won't get that error because you actually have a route with the request object bound to it. But it won't work yet. If we run phpunit at this point, we'll get a null in the face! If you do a dd($request->route()) you'll see that even though it has the info parameter name set up, its parameters array is empty:

IlluminateRoutingRoute {#250
  #uri: "testing/{info}"
  #methods: array:2 [
    0 => "GET"
    1 => "HEAD"
  ]
  #action: array:1 [
    "uses" => null
  ]
  #controller: null
  #defaults: []
  #wheres: []
  #parameters: [] <===================== HERE
  #parameterNames: array:1 [
    0 => "info"
  ]
  #compiled: SymfonyComponentRoutingCompiledRoute {#252
    -variables: array:1 [
      0 => "info"
    ]
    -tokens: array:2 [
      0 => array:4 [
        0 => "variable"
        1 => "/"
        2 => "[^/]++"
        3 => "info"
      ]
      1 => array:2 [
        0 => "text"
        1 => "/testing"
      ]
    ]
    -staticPrefix: "/testing"
    -regex: "#^/testing/(?P<info>[^/]++)$#s"
    -pathVariables: array:1 [
      0 => "info"
    ]
    -hostVariables: []
    -hostRegex: null
    -hostTokens: []
  }
  #router: null
  #container: null
}

所以通過 ['info' =>5]Request 構造函數沒有任何作用.讓我們看看 Route 類,看看它的 $parameters 屬性 正在填充.

So passing that ['info' => 5] to Request constructor has no effect whatsoever. Let's have a look at the Route class and see how its $parameters property is getting populated.

當我們綁定請求 對路由的對象,$parameters 屬性由對 bindParameters() 方法,該方法依次調用 bindPathParameters() 找出路徑特定的參數(我們沒有本例中的主機參數).

When we bind the request object to the route, the $parameters property gets populated by a subsequent call to the bindParameters() method which in turn calls bindPathParameters() to figure out path-specific parameters (we don't have a host parameter in this case).

該方法將請求的解碼路徑與 Symfony 的 SymfonyComponentRoutingCompiledRoute(您也可以在上面的轉儲中看到該正則表達式)并返回作為路徑參數的匹配項.如果路徑與模式不匹配(這是我們的情況),它將為空.

That method matches request's decoded path against a regex of Symfony's SymfonyComponentRoutingCompiledRoute (You can see that regex in the above dump as well) and returns the matches which are path parameters. It will be empty if the path doesn't match the pattern (which is our case).

/**
 * Get the parameter matches for the path portion of the URI.
 *
 * @param  IlluminateHttpRequest  $request
 * @return array
 */
protected function bindPathParameters(Request $request)
{
    preg_match($this->compiled->getRegex(), '/'.$request->decodedPath(), $matches);
    return $matches;
}

問題在于,當沒有實際請求時,$request->decodedPath() 返回與模式不匹配的 /.所以無論如何參數包都是空的.

The problem is that when there's no actual request, that $request->decodedPath() returns / which does not match the pattern. So the parameters bag will be empty, no matter what.

如果您在 Request 類上遵循 decodedPath() 方法,您將深入了解幾個方法,這些方法最終會從 prepareRequestUri() of SymfonyComponentHttpFoundationRequest.在那里,正是在這種方法中,您將找到問題的答案.

If you follow that decodedPath() method on the Request class, you'll go deep through a couple of methods which will finally return a value from prepareRequestUri() of SymfonyComponentHttpFoundationRequest. There, exactly in that method, you'll find the answer to your question.

它通過探測一堆 HTTP 標頭來確定請求 URI.它首先檢查 X_ORIGINAL_URL,然后是 X_REWRITE_URL,然后是其他一些,最后是 REQUEST_URI 標頭.您可以將這些標頭中的任何一個設置為實際欺騙請求 URI 并實現對 http 請求的最小模擬.讓我們看看.

It's figuring out the request URI by probing a bunch of HTTP headers. It first checks for X_ORIGINAL_URL, then X_REWRITE_URL, then a few others and finally for the REQUEST_URI header. You can set either of these headers to actually spoof the request URI and achieve minimum simulation of a http request. Let's see.

<?php

use IlluminateHttpRequest;
use IlluminateRoutingRoute;

class ExampleTest extends TestCase
{
    public function testBasicExample()
    {
        $request = new Request([], [], [], [], [], ['REQUEST_URI' => 'testing/5']);

        $request->setRouteResolver(function () use ($request) {
            return (new Route('GET', 'testing/{info}', []))->bind($request);
        });

        dd($request->route()->parameter('info'));
    }
}

出乎你的意料,它打印出5info 參數的值.

To your surprise, it prints out 5; the value of info parameter.

您可能希望將功能提取到可在您的測試用例中使用的輔助 simulateRequest() 方法或 SimulatesRequests 特性.

You might want to extract the functionality to a helper simulateRequest() method, or a SimulatesRequests trait which can be used across your test cases.

即使絕對不可能像上述方法那樣欺騙請求 URI,您也可以部分模擬請求類并設置您期望的請求 URI.類似的東西:

Even if it was absolutely impossible to spoof the request URI like the approach above, you could partially mock the request class and set your expected request URI. Something along the lines of:

<?php

use IlluminateHttpRequest;
use IlluminateRoutingRoute;

class ExampleTest extends TestCase
{

    public function testBasicExample()
    {
        $requestMock = Mockery::mock(Request::class)
            ->makePartial()
            ->shouldReceive('path')
            ->once()
            ->andReturn('testing/5');

        app()->instance('request', $requestMock->getMock());

        $request = request();

        $request->setRouteResolver(function () use ($request) {
            return (new Route('GET', 'testing/{info}', []))->bind($request);
        });

        dd($request->route()->parameter('info'));
    }
}

這也會打印出5.

這篇關于在 Laravel 測試用例中模擬一個 http 請求并解析路由參數的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!

【網站聲明】本站部分內容來源于互聯(lián)網,旨在幫助大家更快的解決問題,如果有圖片或者內容侵犯了您的權益,請聯(lián)系我們刪除處理,感謝您的支持!

相關文檔推薦

Magento products by categories(按類別劃分的 Magento 產品)
Resource interpreted as image but transferred with MIME type text/html - Magento(資源被解釋為圖像但使用 MIME 類型 text/html 傳輸 - Magento)
Is there an event for customer account registration in Magento?(Magento 中是否有客戶帳戶注冊事件?)
Magento addFieldToFilter: Two fields, match as OR, not AND(Magento addFieldToFilter:兩個字段,匹配為 OR,而不是 AND)
quot;Error 404 Not Foundquot; in Magento Admin Login Page(“未找到錯誤 404在 Magento 管理員登錄頁面)
Get Order Increment Id in Magento(在 Magento 中獲取訂單增量 ID)
主站蜘蛛池模板: 电动球阀_不锈钢电动球阀_电动三通球阀_电动调节球阀_上海湖泉阀门有限公司 | 压缩空气冷冻式干燥机_吸附式干燥机_吸干机_沪盛冷干机 | 睿婕轻钢别墅_钢结构别墅_厂家设计施工报价 | 天津云仓-天津仓储物流-天津云仓一件代发-顺东云仓 | 耳模扫描仪-定制耳机设计软件-DLP打印机-asiga打印机-fitshape「飞特西普」 | 昆明网络公司|云南网络公司|昆明网站建设公司|昆明网页设计|云南网站制作|新媒体运营公司|APP开发|小程序研发|尽在昆明奥远科技有限公司 | LED灯杆屏_LED广告机_户外LED广告机_智慧灯杆_智慧路灯-太龙智显科技(深圳)有限公司 | 干洗店加盟_洗衣店加盟_干洗店设备-伊蔻干洗「武汉总部」 | 油漆辅料厂家_阴阳脚线_艺术漆厂家_内外墙涂料施工_乳胶漆专用防霉腻子粉_轻质粉刷石膏-魔法涂涂 | H型钢切割机,相贯线切割机,数控钻床,数控平面钻,钢结构设备,槽钢切割机,角钢切割机,翻转机,拼焊矫一体机 | 阁楼货架_阁楼平台_仓库仓储设备_重型货架_广州金铁牛货架厂 | 电销卡 防封电销卡 不封号电销卡 电话销售卡 白名单电销卡 电销系统 外呼系统 | 制丸机,小型中药制丸机,全自动制丸机价格-甘肃恒跃制药设备有限公司 | 山东风淋室_201/304不锈钢风淋室净化设备厂家-盛之源风淋室厂家 翻斗式矿车|固定式矿车|曲轨侧卸式矿车|梭式矿车|矿车配件-山东卓力矿车生产厂家 | 奥因-光触媒除甲醛公司-除甲醛加盟公司十大品牌 | 北京环球北美考试院【官方网站】|北京托福培训班|北京托福培训 | 缓蚀除垢剂_循环水阻垢剂_反渗透锅炉阻垢剂_有机硫化物-郑州威大水处理材料有限公司 | 河南中整光饰机械有限公司-抛光机,去毛刺抛光机,精密镜面抛光机,全自动抛光机械设备 | 杭州可当科技有限公司—流量卡_随身WiFi_AI摄像头一站式解决方案 | 伶俐嫂培训学校_月嫂培训班在哪里报名学费是多少_月嫂免费政府培训中心推荐 | 高柔性拖链电缆-聚氨酯卷筒电缆-柔性屏蔽电缆厂家-玖泰电缆 | 亿立分板机_曲线_锯片式_走刀_在线式全自动_铣刀_在线V槽分板机-杭州亿协智能装备有限公司 | 英国公司注册-新加坡公司注册-香港公司开户-离岸公司账户-杭州商标注册-杭州优创企业 | 专业生物有机肥造粒机,粉状有机肥生产线,槽式翻堆机厂家-郑州华之强重工科技有限公司 | 湖南自考_湖南自学考试网 | 中红外QCL激光器-其他连续-半导体连续激光器-筱晓光子 | 开云(中国)Kaiyun·官方网站-登录入口 | 卸料器-卸灰阀-卸料阀-瑞安市天蓝环保设备有限公司 | 陕西安玻璃自动感应门-自动重叠门-磁悬浮平开门厂家【捷申达门业】 | 酒吧霸屏软件_酒吧霸屏系统,酒吧微上墙,夜场霸屏软件,酒吧点歌软件,酒吧互动游戏,酒吧大屏幕软件系统下载 | 橡胶接头|可曲挠橡胶接头|橡胶软接头安装使用教程-上海松夏官方网站 | 青岛球场围网,青岛车间隔离网,青岛机器人围栏,青岛水源地围网,青岛围网,青岛隔离栅-青岛晟腾金属制品有限公司 | 磁力反应釜,高压釜,实验室反应釜,高温高压反应釜-威海自控反应釜有限公司 | 天津仓库出租网-天津电商仓库-天津云仓一件代发-【博程云仓】 | 注塑机-压铸机-塑料注塑机-卧式注塑机-高速注塑机-单缸注塑机厂家-广东联升精密智能装备科技有限公司 | 全自动变压器变比组别测试仪-手持式直流电阻测试仪-上海来扬电气 | 电伴热系统施工_仪表电伴热保温箱厂家_沃安电伴热管缆工业技术(济南)有限公司 | 馋嘴餐饮网_餐饮加盟店火爆好项目_餐饮连锁品牌加盟指南创业平台 | 合肥钣金加工-安徽激光切割加工-机箱机柜加工厂家-合肥通快 | 海日牌清洗剂-打造带电清洗剂、工业清洗剂等清洗剂国内一线品牌 海外整合营销-独立站营销-社交媒体运营_广州甲壳虫跨境网络服务 | 刹车盘机床-刹车盘生产线-龙口亨嘉智能装备 |