php - 测试 Laravel 密码重置
问题描述
我正在实现https://laravel.com/docs/8.x/passwords的 Laravel 文档中描述的密码重置功能。我重置密码的方法如下:
public function doPasswordReset(Request $request)
{
$request->validate([
'token' => 'required',
'email' => 'required|email',
'password' => 'required|min:8|confirmed',
]);
$status = Password::reset(
$request->only('email', 'password', 'password_confirmation', 'token'),
function ($user, $password) {
$user->forceFill([
'password' => Hash::make($password)
]);
//remember token not needed
//->setRememberToken(Str::random(60));
$user->save();
event(new PasswordReset($user));
}
);
return $status === Password::PASSWORD_RESET
? redirect()->route('login')->with('status', __($status))
: back()->withErrors(['email' => [__($status)]]);
}
我对这种方法的测试是:
/** @test */
public function the_user_can_update_their_password()
{
ParentUser::factory()->create([
'email' => 'user@domain.com',
'password' => Hash::make('oldpassword')
]);
$token = Password::createToken(ParentUser::first());
Password::shouldReceive('reset')
->once()
->withSomeofArgs([
'email' => 'user@domain.com',
'password' => 'newpassword',
'password_confirmation' => 'newpassword',
'token' => $token
])
->andReturn(Password::PASSWORD_RESET);
$response = $this->post(route('password.update'), [
'email' => 'user@domain.com',
'password' => 'newpassword',
'password_confirmation' => 'newpassword',
'token' => $token
]);
$response->assertRedirect(route('login'));
//failures from here
$this->assertEquals(Hash::make('newpassword'), Hash::make(ParentUser::first()->password));
$this->assertNotEquals(Hash::make('oldpassword'), Hash::make(ParentUser::first()->password));
Event::fake();
Event::assertDispatched(PasswordReset::class, ParentUser::first());
}
我的问题是最后三个断言失败了。我意识到这种情况正在发生,因为我的模拟没有调用闭包来影响密码更改并引发事件。所以我的问题是是否可以模拟函数调用的一些参数。
我正在考虑的一种解决方案是将闭包分解为自己的方法并单独测试。在没有其他任何东西的情况下,我认为这可能是唯一的方法。
解决方案
Hash::make()
不会为任何给定值生成相同的哈希。看一看:
Hash::make('newpassword') == Hash::make('newpassword')
// false
由于这是false
,我希望assetEquals()
在这里失败,因为它们的值不相等。相反,看看Hash::check()
方法:
Hash::check('newpassword', Hash::make('newpassword'))
// true
您可以assertTrue()
改为使用它,例如:
$this->assertTrue(Hash::check('newpassword', ParentUser::first()->password));
$this->assertFalse(Hash::check('oldpassword', ParentUser::first()->password));
旁注,->password
应该已经是 Hashed,所以没有必要将它包装在另一个中Hash::make()
,因为你会有一个“Hash-of-a-hash”,这会使Hash::check()
.
推荐阅读
- javascript - Chart.js 雷达背景颜色背景
- r - 我的数值前面的分号
- django - 视图和模板中的设置值问题
- mysql - 为什么我不能以这种方式创建表?
- android - 如何绘制具有负值和正值的范围图 MpAndroidChart?
- wcf - {error: (403) Forbidden."} 带有传输和证书凭据的 WCF basicHttpBinding
- jmeter-plugins - JSON 响应失败 - 没有可用的消息错误
- swift - 在动态创建的 NSButton 复选框上获取发件人
- python - 在python中以列表形式读取数据?
- javascript - 当我使用 loadJSON 加载谷歌地图标记时出现问题