訳あって laravel 5.6 に upgrade したら、 tests/* で使ってた \Illuminate\Support\Facades\Hash::shouldReceive('make')->andReturn('dummy-password');
が使えなくなったので、取り敢えずの代替方法を用意した。
5.5.* から 5.6.* に Upgrade した際の簡易メモ。
- composer.json を 5.6 の状態に合わせる
-
./config/hashing.php
と./config/logging.php
を 5.6 から取得してくる -
./config/app.php
からLogging Configuration
セクションを削除する -
./config/broadcasting.php
を 5.6.x の内容に合わせる(connections -> pusher -> options
の内容を 5.6.x の通りに追加) -
./config/filesystems.php
を 5.6.x の内容に合わせる(disks -> s3 -> 'url' => env('AWS_URL'),
を追加) -
./config/queue.php
を 5.6.x の内容に合わせる(connections -> sqs -> key, secret, prefix, queue, region
とconnections -> redis ->block_for
を修正)
これらを修正した上で、 phpunit を走らせると、 Hash::shouldReceive('make')
で尽くコケた。
まぁ、当然なんやけど。
結論
以下のような helper method を TestCase.php に追加した。
protected function freezeBcrypt($fixedPassword)
{
$bcryptHasher = Mockery::mock(\Illuminate\Hashing\BcryptHasher::class);
$bcryptHasher->shouldReceive('make')->andReturn($fixedPassword);
$hashManager = Mockery::mock(\Illuminate\Hashing\HashManager::class);
$hashManager->shouldReceive('driver')->withArgs(['bcrypt'])->andReturn($bcryptHasher);
app()->bind('hash', function () use ($hashManager) {
return $hashManager;
});
}
times()
などは検査してないので、もし、それらが必要ならば適切に修正するべきだと思う。
使い方は言うまでもなく、各 Test File で $this->freezeBcrypt('dummy-passowrd');
とかして使う。
どのように対応したか
まずは 5.6.x の bcrypt() helper の中身を見る
bcrypt() helper の中身は、 /vendor/laravel/framework/src/Illuminate/Foundation/helpers.php
に書いてある。
※ 任意の場所(適当な Controller とか web.php とかお好きな場所)に bcrypt();
と書き、 PhpStorm などから、 記載した bcrypt()
helper を cmd + (click)
すると、実装コードにジャンプする。
if (! function_exists('bcrypt')) {
/**
* Hash the given value against the bcrypt algorithm.
*
* @param string $value
* @param array $options
* @return string
*/
function bcrypt($value, $options = [])
{
return app('hash')->driver('bcrypt')->make($value, $options);
}
}
※ 現時点の 5.6.3 では、上記( https://github.com/laravel/framework/blob/v5.6.3/src/Illuminate/Foundation/helpers.php#L186-L198 )となっていた。
5.5.x から何が変わったのか
5.5.x の頃のコードを確認してみる( https://github.com/laravel/framework/blob/v5.5.34/src/Illuminate/Foundation/helpers.php#L186-L198 )と、以下のようになっていた。
if (! function_exists('bcrypt')) {
/**
* Hash the given value.
*
* @param string $value
* @param array $options
* @return string
*/
function bcrypt($value, $options = [])
{
return app('hash')->make($value, $options);
}
}
https://laravel.com/docs/5.6/upgrade#upgrade-5.6.0 の H3 tag Hashing
の箇所を見ても分かる通り、 config/hashing.php
の設定で bcrypt
と argon
をサポートしたよってことらしい。
それによって、 driver
を選択するステップが増えてる。
※ ちなみに 5.6 の https://laravel.com/docs/5.6/hashing を見る限り、 argon
は requires PHP 7.2.0 or greater.
だそうです。
取り敢えず、今は bcrypt のままで進めるとして、 ./config/hashing.php
は driver -> bcrypt
としておく。(5.6.x から取得したデフォルトの状態のまま。)
driver 選択のステップを吸収する
取り敢えずは、素直に、 app('hash')
を差し替えるアプローチとした。
-
app('hash')
を$hashManager
に差し替える -
$hashManager
のdriver
メソッドを呼ぶと、$bcryptHasher
を返却するようにしておく -
$bcryptHasher
はmake
メソッドを呼ぶと、$fixedPassword
を返却する。
という実装が前述と同じ以下のコード。
protected function freezeBcrypt($fixedPassword)
{
$bcryptHasher = Mockery::mock(\Illuminate\Hashing\BcryptHasher::class);
$bcryptHasher->shouldReceive('make')->andReturn($fixedPassword);
$hashManager = Mockery::mock(\Illuminate\Hashing\HashManager::class);
$hashManager->shouldReceive('driver')->withArgs(['bcrypt'])->andReturn($bcryptHasher);
app()->bind('hash', function () use ($hashManager) {
return $hashManager;
});
}
どこまで担保するべきか、という問題はあるけど、取り敢えず、今回は times() の検証は行ってない。
最後に
事前に Hash::shouldReceive('make')->andReturn('dummy-password');
自体をちゃんと TestCase の helper Method にしておけば良かった。
散見された為、修正して回る羽目になった。
いつか driver argon
も times()
も対応できるようにしたいね。
あと、 app()
を経由して差し替えるアプローチはあまり望ましくないかもしれないので、容量用法をお守り下さい
という気持ちを忘れずにするのが大切かも知れない。
というメモ。