Comment j'ai essayé d'améliorer Laravel et ne fait qu'empirer les choses

introduction

Laravel est un framework PHP sympa, nous l'utilisons tout le temps dans l'entreprise. Mais comme vous le savez, rien au monde n'est parfait, vous pouvez toujours suggérer des améliorations.





Il y a quelques semaines, j'ai essayé de faire une petite amélioration sur la zone de test de Laravel, ouvert deux pull requests ( # 1 et # 2 ). Les deux pull requests ont été rejetées par l'auteur du framework, Taylor, mais à la fin, le même jour, il a publié sa propre implémentation de la même fonctionnalité, dont il s'est même vanté sur Twitter. Et, ô dieux, la réalisation est terrible!





Le contexte

Nous préférons les tests d'intégration seuls, car ils vous permettent d'atteindre un bon équilibre entre le coût des tests automatisés et la confiance dans vos déploiements. Souvent, dans nos tests d'intégration, nous faisons quelque chose au nom de l'utilisateur, puis nous voulons nous assurer que l'utilisateur a finalement reçu une sorte de lettre. Pour ce faire, Laravel implémente de manière standard:





<?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();
      
      







, , . , , , .





Notre objectif était de tester le code de combat - méthodes render () et send (). Nous avons testé une nouvelle méthode nouvellement créée que personne n'utilisera dans la pratique.





Jetons un coup d'œil à cette méthode:





<?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];
    });
}
      
      







Oh, pas une méthode, mais un monstre!





Non seulement il est très difficile à lire, mais il répète également beaucoup de lignes de la méthode render (), il y a donc maintenant une chance qu'un jour les méthodes divergent. Et chaque fois que vous modifiez render (), vous devez maintenant vous rappeler de corriger renderForAssertions ().





À mon avis, il est fondamentalement faux de tester des méthodes spécialement conçues pour les tests, au lieu du vrai code. C'est une sorte de non-sens.





Je trouve qu'avec ce commit, mon framework préféré a un peu empiré :(








All Articles