Laravelを改善しようとしたが、悪化させた方法

前書き

LaravelはクールなPHPフレームワークであり、会社では常に使用しています。しかし、ご存知のように、世界で完璧なものはありません。いつでも改善を提案できます。





数週間前、私はLaravelテストエリアで1つの小さな改善を試み、2つのプルリクエスト(#1#2)を開きましたフレームワークの作成者であるテイラーは両方のプルリクエストを拒否しましたが、最終的には彼自身が同じ機能の独自の実装を同じ日に公開し、Twitterでもそれを自慢していました。そして、なんてこった、実現はひどいです!





環境

自動テストのコストと展開の信頼性のバランスをとることができるため、統合テストを独自に行うことをお勧めします。多くの場合、統合テストでは、ユーザーに代わって何かを実行し、ユーザーが最終的に何らかの手紙を受け取ったことを確認したいと考えています。これを行うために、Laravelは標準的な方法を実装します。





<?php
public function test_orders_can_be_shipped()
{
    Mail::fake();

    Mail::assertSent(OrderShipped::class);
}
      
      



, , , - , ? , " - ", " - ".





Laravel , :





<?php
Mail::assertSent(OrderShipped::class, function ($mail) use ($user) {
    return $mail->hasTo($user->email) &&
           $mail->somePublicProperty == 'someValue';
});
      
      



, - To/Cc/Bcc (, , ). Mailable Laravel , . render() Mailable, :





<?php
public function render()
{
    return $this->withLocale($this->locale, function () {
        Container::getInstance()->call([$this, 'build']);
        return Container::getInstance()->make('mailer')->render(
            $this->buildView(), $this->buildViewData()
        );
    });
}
      
      



render(), . , buildView() buildViewData() - .





, :





  • Mailable, . . .





  • Mailable Macroable, . , Mailable , "with", Macroable . .





  • - -, proxy, Mailable, , , , - seeInHtml(), seeInText(). .





( -) Mockery, Mailable , :





<?php
public function email_confirmation_is_correct()
{
    Mail::fake();

    event(new TestEvent());
    config(['app.name' => 'Test App']);

    Mail::assertSent(TestMail::class, function (TestMail $mail) {
        return $mail->hasTo('test@test.com') 
          && $mail->seeInHtml('shipped')
          && $mail->dontSeeInHtml('failed') 
          && $mail->seeInText('Test App');
        });
    }
      
      







, API - Laravel, - , ( MailFake, TestMailable). production- .





, , - - :





, , - , , , , - ! API , "assert".





– , , .





– , , , . , – .





production- Mailable, , . , , .





, , Mailable:





<?php
/**
 * @param  string  $string
 * @return void
 */
public function assertSeeInText($string)
{
    [$html, $text] = $this->renderForAssertions();

    PHPUnit::assertTrue(
        Str::contains($text, $string),
        "Did not see expected text [{$string}] within text email body."
    );
}
      
      







:





  • Laravel, production-, . , - . , - MailFake, - Mailable





  • Mailable PHPUnit, development-only, composer.json. , production-





:





[$html, $text] = $this->renderForAssertions();
      
      







, , . , , , .





私たちの目標は、戦闘コードをテストすることでした-render()メソッドとsend()メソッド。新しく作成された新しいメソッドをテストしました。これは実際には誰も使用しません。





この方法を見てみましょう:





<?php
protected function renderForAssertions()
{
    if ($this->assertionableRenderStrings) {
        return $this->assertionableRenderStrings;
    }

    return $this->assertionableRenderStrings = $this->withLocale($this->locale, function () {
        Container::getInstance()->call([$this, 'build']);

        $html = Container::getInstance()->make('mailer')->render(
            $view = $this->buildView(), $this->buildViewData()
        );

        $text = $view['text'] ?? '';

        if (! empty($text) && ! $text instanceof Htmlable) {
            $text = Container::getInstance()->make('mailer')->render(
                $view['text'], $this->buildViewData()
            );
        }

        return [(string) $html, (string) $text];
    });
}
      
      







ああ、方法ではなく、モンスター!





読みにくいだけでなく、render()メソッドからも多くの行が繰り返されるため、いつかメソッドが分岐する可能性があります。また、render()を編集するたびに、renderForAssertions()を修正することを忘れないでください。





私の意見では、実際のコードではなく、テスト用に特別に設計されたメソッドをテストすることは根本的に間違っています。これはある種のナンセンスです。





このコミットにより、私のお気に入りのフレームワークが少し悪化したことがわかりました:(








All Articles