laravel created_at 时间戳_使用 HTTP 测试测试 Laravel 中间件

bb1b9060baf90157f22edfb9720cefe7.png
文章转发自专业的Laravel开发者社区,原始链接:https://learnku.com/laravel/t/34002

在本文中,我将展示一个使用 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中间件,以下是我们要测试的内容,以确保中间件按预期工作:

  1. 除了之外的任何HTTP动词 POST 都应该引起 403 Forbidden 响应。
  2. 无效的签名应该创建 403 Forbidden 响应。
  3. 有效签名应该通过并命中可调用的路由。
  4. 旧的时间戳应该引起 403 Forbidden 响应。

测试无效的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_methods

Testing 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应用程序,那么这将是一个不错的资源。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/244325.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux 内核主线,为AM335x移植Linux内核主线代码(41)Ethernet结论篇

一口老血喷到屏幕上&#xff01;请自动略过之前的第36&#xff5e;40小节_&#xff01;&#xff01;&#xff01;https://www.tuicool.com/articles/UvmuEv我的电路板存在的问题是&#xff1a;由于布线(杜邦线)导致的干扰&#xff0c;只能通信在10Mbps&#xff0c;而不能通信在…

动物识别专家系统python_Python有哪些作用?

Python是什么呢&#xff1f;Python是一种全栈的开发语言&#xff0c;如果能学好Python&#xff0c;前端、后端、测试、大数据分析、爬虫等这些工作你都能胜任。那Python有哪些作用呢&#xff1f;Python主要有以下四大主要应用&#xff1a;网络爬虫网站开发人工智能自动化运维接…

linux 命令下删除字符,【Linux基础】tr命令替换和删除字符

cat t.txtabcdacat t.txt |tr abc xyzxyzdxcat t.txtabcda备注&#xff1a;凡是在t.txt文件中出现的"a"字母&#xff0c;都替换成"x"字母&#xff0c;"b"字母替换为"y"字母&#xff0c;"c"字母替换为"z"字母。而不…

python ssh登陆模块_使用python的Paramiko模块登陆SSH

paramiko是用Python语言写的一个模块&#xff0c;遵循SSH2协议&#xff0c;支持以加密和认证的方式&#xff0c;进行远程服务器的连接。python的paramiko模块可以方便的实现ssh登录&#xff0c;并执行命令。1. paramiko模块安装1.1安装pycrypto库pycrypto库安装方法python setu…

linux mint图标大小,Cinnamon:LinuxMint 15桌面设置小技巧

touchwiz自身也在做不断的革新&#xff0c;例如7屏分页&#xff0c;桌面切换3d效果&#xff0c;增强型的下拉菜单设置等。win10多桌面最多可以支持7个桌面开启&#xff0c;而且win10切换多桌面是有快捷键的&#xff0c;可以帮助用户迅速切换或创建以及关闭多桌面。切换方法一&a…

操作系统源代码_国产操作系统“之光”?Windows XP绝密源代码泄露,BT种子已在网上疯传...

微软的Windows操作系统是目前使用人数最多、覆盖最广的桌面操作系统&#xff0c;从安全角度来看&#xff0c;其系统源代码对于公众而言可以说是绝密。不过......现在......&#xff0c;黑客在4Chan平台上以BT种子文件的形式在线泄漏了多个旧Windows版本的源代码&#xff0c;包括…

linux设置多语言环境,怎么为Linux系统配置多语言环境?

这篇文章主要讲述了怎么为Linux系统配置多语言环境的基本方法&#xff0c;其中还包括编码的修改方法&#xff0c;我们就拿用户使用最多的Ubuntu和CentOS这两个为例子吧。需要的朋友可以参考下。修改 /etc/sysconfig/i18n 文件&#xff0c;如LANG“en_US.UTF-8”&#xff0c;xwi…

轴承新旧型号对照表_精密机床主轴轴承,高端轴承进口清关报关流程

精密机床的主轴对轴承精度的要求非常高&#xff0c;我国目前在这一技术上仍然处于一片空白&#xff0c;那么高精度的轴承要怎么进口呢&#xff1f;高精度轴承进口这块其他国家管控得比较严格&#xff0c;高精度轴承的进口又会遇到哪些问题呢&#xff1f;在我们的生活中轴承几乎…

linux禁止切换到root,linux禁止普通用户切换至root用户的实例讲解

在上正文之前&#xff0c;我想先将一些基础的linux用户以及用户组的相关命令&#xff1a;1、添加用户useradd [-g group] [-d user_home_directory] [-p “your password”] Username-g 表示设置新增用户所属用户组-d 表示设置新增用户的主目录-p 表示设置新增用户的登录密码还…

python中new方法详解及_Python中new方法的详解

new_ 方法是什么&#xff1f;__new__方法其实就是创建对象的方法new()方法是在类准备将自身实例化时调用。一个类可以有多个位置参数和多个命名参数&#xff0c;而在实例化开始之后&#xff0c;在调用 init()方法之前&#xff0c;Python首先调用new()方法&#xff1a;def new(c…

linux 子域dns,linux下搭建DNS子域及相关授权详解

linux下搭建DNS子域及相关授权详解forward功能是本地无法解析的域名&#xff0c;转发给指定DNS服务器forward only; 所有无法解析的域名&#xff0c;都转发给指定DNS服务器&#xff0c;必须有解析结果forward first;无法解析的域名&#xff0c;转发给指定DNS服务器&#xff0c;…

python堆排序求topn_Java堆排序,取得前TopN个数

import java.util.Random;/*** Created with IntelliJ IDEA.* User: pengfei.hpf* Date: 14-4-29* Time: 上午11:45* To change this template use File | Settings | File Templates.*/public class HeapSortUtil {/*** 用堆排序方法 找出前N个最大的数* originalArray 原始数…

开机自启动程序关闭方法_电脑非常卡,总有软件偷偷自启动?学会这1招,永久关闭它们!...

小编有一个朋友&#xff0c;前段子发微信问我&#xff0c;说他的电脑非常卡&#xff0c;重装电脑后&#xff0c;会好转许多&#xff0c;非常流畅&#xff0c;但是过了几天又卡了。我问了他的电脑配置&#xff0c;首先电脑的配置是绝对ok。当前一流水平&#xff0c;后来我远程操…

linux c socket编程详解,Linux c 网络socket编程

#include int main(){int sockfd,new_fd;struct sockaddr_in my_addr;struct sockaddr_in their_addr;int sin_size;//建立TCP套接口if((sockfd socket(AF_INET,SOCK_STrEAM,0))-1){perror("socket");exit(1);}//初始化结构体&#xff0c;并绑定2323端口my_addr.sin…

python饮料购买_Python实现的一个自动售饮料程序代码分享

写这个程序的时候&#xff0c;我已学习Python将近有一百个小时&#xff0c;在CSDN上看到有人求助使用Python如何写一个自动售饮料的程序&#xff0c;我一想&#xff0c;试试写一个实用的售货程序。当然&#xff0c;只是实现基本功能&#xff0c;欢迎高手指点&#xff0c;新手学…

C语言进制的格式字符,GB汉字文件转换成C语言Unicode十六进制字符串格式

可以用在编程环境只能用GB&#xff0c;但程序中的汉字字符串需要用C语言的Unicode十六进制字符串格式表示。可以先在字符串中直接输入汉字&#xff0c;再用此程序转换。源代码用C#//ascii & GB to unicode hexadecimal string for C language//chinese GB code : "啊&…

python udp客户端 服务器实现方式_python3实现UDP协议的简单服务器和客户端

利用python中的socket模块中的来实现UDP协议&#xff0c;这里写一个简单的服务器和客户端。为了说明网络编程中UDP的应用&#xff0c;这里就不写图形化了&#xff0c;在两台电脑上分别打开UDP的客户端和服务端就可以了。UDP:用户数据报协议&#xff0c;是一个面向无连接的协议。…

C语言实现上三角蛇形矩阵不用数组,蛇形矩阵c语言实现

【问题描述】蛇形矩阵是由1开始的自然数依次排列成的一个矩阵上三角形。如&#xff1a;1 3 6 10 152 5 9 144 8 137 1211本题要求根据输入的行数要求&#xff0c;输出对应的一个蛇形上三角矩阵【输入形式】一个整数【输出形式】与之对应的蛇形上三角矩阵【样例输入】5【样例输出…

蒙特卡洛模拟_蒙特卡洛模拟法求期权价值

今年跟朋友讨论了一个期权问题。“Earn Out”方式并购下的金融工具确认。大致条款如下(非真实情况)&#xff1a;收购一家标的企业估值15000万元。盈利预测情况如下&#xff1a;收购协议中约定了第一期支付对价50%。同时第二期对价于2021年支付50%。同时若低于2021年净利润低于9…

尚展垒等编著c语言程序设计,C语言程序设计技术实践指导

本书是《C语言程序设计技术》(尚展垒等编著&#xff0c;中国铁道出版社出版)配套使用的学习用书&#xff0c;每个实验对应主教材的相关内容。本书所使用的运行环境是Visual Studio 2010&#xff0c;与全国计算机等级考试(二级C语言)的运行环境一致。本书的每个实验项目均在 Vis…