LoginSignup
0
0

More than 5 years have passed since last update.

Laravel 5.6 で \Illuminate\Support\Facades\Hash::shouldReceive('make') が使えなくなったので tests 用の代わりの方法を用意した

Last updated at Posted at 2018-02-13

訳あって 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, regionconnections -> redis ->block_for を修正)

これらを修正した上で、 phpunit を走らせると、 Hash::shouldReceive('make') で尽くコケた。

まぁ、当然なんやけど。

結論

以下のような helper method を TestCase.php に追加した。

tests/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) すると、実装コードにジャンプする。

/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php
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 )と、以下のようになっていた。

/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php
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 の設定で bcryptargon をサポートしたよってことらしい。

それによって、 driver を選択するステップが増えてる。

※ ちなみに 5.6 の https://laravel.com/docs/5.6/hashing を見る限り、 argonrequires PHP 7.2.0 or greater. だそうです。

取り敢えず、今は bcrypt のままで進めるとして、 ./config/hashing.phpdriver -> bcrypt としておく。(5.6.x から取得したデフォルトの状態のまま。)

driver 選択のステップを吸収する

取り敢えずは、素直に、 app('hash') を差し替えるアプローチとした。

  • app('hash')$hashManager に差し替える
  • $hashManagerdriver メソッドを呼ぶと、 $bcryptHasher を返却するようにしておく
  • $bcryptHashermake メソッドを呼ぶと、 $fixedPassword を返却する。

という実装が前述と同じ以下のコード。

tests/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() の検証は行ってない。

最後に

事前に Hash::shouldReceive('make')->andReturn('dummy-password'); 自体をちゃんと TestCase の helper Method にしておけば良かった。

散見された為、修正して回る羽目になった。

いつか driver argontimes() も対応できるようにしたいね。

あと、 app() を経由して差し替えるアプローチはあまり望ましくないかもしれないので、容量用法をお守り下さいという気持ちを忘れずにするのが大切かも知れない。

というメモ。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0