laravel created_at 时间戳_使用 HTTP 测试测试 Laravel 中间件
在本文中,我將展示一個使用 HTTP 測試中間件的實例。HTTP 級測試更能適應變化,可讀性更強。
在最近與 Adam Wathan 和 Taylor Otwell 合拍的《全棧廣播》(http://www.fullstackradio.com/72) 節目中,聽到他們在 HTTP 測試中發現了許多實用價值,令人耳目一新。我發現 HTTP 測試更易編寫和維護,但我確實覺得我在測試 Wrong? ,或沒有模擬(對象),隔離每一測試項在作弊一樣。如果你還沒有聽過這一集的話,請聽一聽,里面充滿了好的、實用的測試建議。
介紹
今年早些時候,我構建了一個中間件,用于在我的一個項目上驗證和保護Mailgun webhook,并在Laravel News上的 用Mailgun對Laravel中的電子郵件進行入站處理 中對此進行了描述。 總之,我將演示如何在處理入站電子郵件時使用Laravel中間件驗證Mailgun webhook(以確保webhook 實際上 來自Mailgun)。
在設置 Mailgun webhook 的核心部分時,作為 HTTP POST 有效負載部分的簽名建議使用rquest提供的簽名、時間戳和令牌來驗證,從而保護您的 webhook。這是我發布的完整中間件:
<?phpnamespace AppHttpMiddleware;use Closure; use IlluminateHttpResponse;class ValidateMailgunWebhook {public function handle($request, Closure $next){if (!$request->isMethod('post')) {abort(Response::HTTP_FORBIDDEN, 'Only POST requests are allowed.');}if ($this->verify($request)) {return $next($request);}abort(Response::HTTP_FORBIDDEN, 'The webhook signature was invalid.');}protected function buildSignature($request){return hash_hmac('sha256',sprintf('%s%s', $request->input('timestamp'), $request->input('token')),config('services.mailgun.secret'));}protected function verify($request){if (abs(time() - $request->input('timestamp')) > 15) {return false;}return $this->buildSignature($request) === $request->input('signature');} }該中間件只接受 POST 請求,并將傳入的簽名與使用 Mailgun 密鑰生成的簽名進行比較。
我已經看到了各種測試中間件的方法,例如直接在單元測試中構建它,根據需要模擬對象,以及直接運行中間件。 在這篇文章中,我將向你展示如何使用更高級別的 HTTP 測試來測試此中間件。 你的整個堆棧將在測試中運行,讓你更有信心 你的應用程序將會按預期工作。
將測試不直接綁定到特定的中間件實現 這是你能了解到的一個重要的福利。 我們可以完全重構中間件,而不需要更改任何測試或更新模擬來驗證中間件是否正常工作。 我相信你會發現這些測試將會更加健壯。
配置
讓我們使用示例Laravel 5.5項目快速構建對上述中間件的測試:
$ laravel new middleware-tests# 切換到 middleware-tests 文件夾 $ cd $_$ php artisan make:middleware ValidateMailgunWebhook獲取上面的中間件代碼并將其粘貼到此中間件文件中。
接下來,將此中間件添加到 app/Http/Kernel.php 文件中:
protected $routeMiddleware = [// ...'mailgun.webhook' => AppHttpMiddlewareValidateMailgunWebhook::class, ];編寫HTTP測試
我們準備針對這個中間件編寫一些測試,我們甚至不必定義任何路由routes/api.php來測試它!
首先,讓我們創建功能測試文件:
$ php artisan make:test SecureMailgunWebhookTest查看Mailgun中間件,以下是我們要測試的內容,以確保中間件按預期工作:
測試無效的HTTP方法
有了這個介紹,讓我們編寫第一個測試并設置我們的測試。
使用以下內容更新SecureMailgunWebhookTest文件:
<?phpnamespace TestsFeature;use TestsTestCase; use SymfonyComponentHttpFoundationResponse; use SymfonyComponentHttpKernelExceptionHttpException;class SecureMailgunWebhookTest extends TestCase {protected function setUp(){parent::setUp();config()->set('services.mailgun.secret', 'secret');Route::middleware('mailgun.webhook')->any('/_test/webhook', function () {return 'OK';});}/** @test */public function it_forbids_non_post_methods(){$this->withoutExceptionHandling();$exceptionCount = 0;$httpVerbs = ['get', 'put', 'patch', 'delete'];foreach ($httpVerbs as $httpVerb) {try {$response = $this->$httpVerb('/_test/webhook');} catch (HttpException $e) {$exceptionCount++;$this->assertEquals(Response::HTTP_FORBIDDEN, $e->getStatusCode());$this->assertEquals('Only POST requests are allowed.', $e->getMessage());}}if (count($httpVerbs) === $exceptionCount) {return;}$this->fail('Expected a 403 forbidden');} }在 setUp() 方法中,我們定義一個假的 Mailgun 密鑰,這樣我們就可以針對這個密鑰編寫我們的測試,然后使用 any() 路由方法定義一個全局(catch-all)路由。 我們的路由將允許我們使用虛假的測試路由來使用中間件發出 HTTP 請求。
在 Laravel 5.5 中引入了 withoutExceptionHandling() 這個方法,這意味著我們可以在測試中自己來捕獲拋出的異常,來替代使用 HTTP 響應來呈現這種異常。
try/catch 將會確保為每個 HTTP 請求捕獲到 HttpException ,還會提供一個遞增的異常計數器。如果捕獲異常的數量與我們測試的 HTTP 請求的數量匹配,則測試通過。否則的話,如果我們的請求沒有引起異常, $this->fail() 方法將會被調用。
與使用注釋相比,我更喜歡捕獲和斷言異常的方法。它會讓我感覺到更清楚,同時我還可以對異常進行斷言,以確保異常是我所期望的。
您可以使用以下 PhpUnit 命令直接運行中間件特性測試::
# Run all tests in the file $ ./vendor/bin/phpunit tests/Feature/SecureMailgunWebhookTest.php# Filter a specific method $ ./vendor/bin/phpunit tests/Feature/SecureMailgunWebhookTest.php --filter=it_forbids_non_post_methodsTesting an Invalid Signature
下一個測試驗證無效簽名是否會導致 403 Forbidden error。這個測試與第一個測試不同,它使用的是 POST 方法,但發送無效的請求數據:
/** @test */ public function it_aborts_with_an_invalid_signature() {$this->withoutExceptionHandling();try {$this->post('/_test/webhook', ['timestamp' => abs(time() - 100),'token' => 'invalid-token','signature' => 'invalid-signature',]);} catch (HttpException $e) {$this->assertEquals(Response::HTTP_FORBIDDEN, $e->getStatusCode());$this->assertEquals('The webhook signature was invalid.', $e->getMessage());return;}$this->fail('Expected the webhook signature to be invalid.'); }我們傳遞將導致無效簽名的假數據,然后斷言在 HttpException中設置了正確的響應狀態和消息。
測試有效簽名
當 webhook 發送有效簽名時,路由將處理響應,而不會中斷中間件。中間件調用verify(),然后在簽名匹配時調用$next():
if ($this->verify($request)) {return $next($request); }要編寫此測試,我們需要發送有效的簽名、時間戳和令牌。我們將在測試類中構建 SHA-256 hash 版本,它幾乎是中間件內相同方法的副本。中間件和我們的測試都將使用在setup()方法中配置的services.mailgun.secret密鑰:
/** @test */ public function it_passes_with_a_valid_signature() {$this->withoutExceptionHandling();$timestamp = time();$token = 'token';$response = $this->post('/_test/webhook', ['timestamp' => $timestamp,'token' => $token,'signature' => $this->buildSignature($timestamp, $token),]);$this->assertEquals('OK', $response->getContent()); }protected function buildSignature($timestamp, $token) {return hash_hmac('sha256',sprintf('%s%s', $timestamp, $token),config('services.mailgun.secret')); }我們的測試在中間件中使用相同代碼構建簽名,因此我們可以生成中間件期望的有效簽名。 在測試結束時,我們斷言在測試路徑中返回的響應內容等于 "OK”。
使用舊時間戳測試失敗
我們的中間件采取的另一個預防措施是,如果 timestamp 應用是舊的,則不允許請求繼續進行。 測試類似于我們斷言失敗的其他測試,但是這次我們使一切有效(簽名和令牌)除了 時間戳之外:
/** @test */ public function it_fails_with_an_old_timestamp() {try {$this->withoutExceptionHandling();$timestamp = abs(time() - 16);$token = 'token';$response = $this->post('/_test/webhook', ['timestamp' => $timestamp,'token' => $token,'signature' => $this->buildSignature($timestamp, $token),]);} catch (HttpException $e) {$this->assertEquals(Response::HTTP_FORBIDDEN, $e->getStatusCode());$this->assertEquals('The webhook signature was invalid.', $e->getMessage());return;}$this->fail('The timestamp should have failed verification.'); }密切關注 $timestamp = abs(time() - 16); 這將使中間件時間戳比較無效。
學習更多
這是一個在 HTTP 級別測試中間件的快速呈現。我更喜歡這種級別的測試,因為在中間件上使用 mocks (假數據)可能會很乏味,而且會綁定到特定的實現。如果我選擇稍后重構,很可能需要重寫我的測試以匹配新的中間件。通過 HTTP 測試,我可以自由地重構中間件,并期望得到相同的結果。
在 Laravel 中編寫[HTTP 測試](https://laravel.com/docs/5.5/http-tests) 非常簡便,我發現自己在這個級別上做了更多的測試。我相信我寫的測試很容易理解,因為我們不 mock (模擬)任何東西。您應熟練使用Laravel 測試套件的斷言(功能)來測試。這些工具使你的測試工作更容易,我敢說更有趣。
如果你不熟悉測試, 你也可以在 Laravel News中查看Test Driven Laravel 。我也經歷過這個過程;如果您剛剛開始測試Web應用程序,那么這將是一個不錯的資源。
總結
以上是生活随笔為你收集整理的laravel created_at 时间戳_使用 HTTP 测试测试 Laravel 中间件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 美国航空取消上万航班!旅客疯狂购买苹果A
- 下一篇: 我国重大科技基础设施,高能同步辐射光源增