Cómo intenté mejorar Laravel y solo lo empeoré

Introducción

Laravel es un framework PHP genial, lo usamos todo el tiempo en la empresa. Pero como sabes, nada en el mundo es perfecto, siempre puedes sugerir mejoras.





Hace unas semanas traté de hacer una pequeña mejora en el área de prueba de Laravel, abrí dos solicitudes de extracción ( # 1 y # 2 ). Ambas solicitudes de extracción fueron rechazadas por el autor del framework, Taylor, pero al final, el mismo día, publicó su propia implementación de la misma funcionalidad, de la que incluso se jactó en Twitter. ¡Y, oh dioses, la comprensión es terrible!





Contexto

Preferimos las pruebas de integración por nuestra cuenta, ya que le permite lograr un buen equilibrio entre el costo de las pruebas automatizadas y la confianza en sus implementaciones. A menudo, en nuestras pruebas de integración, hacemos algo en nombre del usuario y luego queremos asegurarnos de que el usuario finalmente haya recibido algún tipo de carta. Para hacer esto, Laravel implementa la forma estándar:





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







, , . , , , .





Nuestro objetivo era probar el código de combate: los métodos render () y send (). Probamos el nuevo método recién creado, que nadie utilizará en la práctica.





Echemos un vistazo a este método:





<?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, no un método, sino un monstruo!





No solo es muy difícil de leer, sino que también repite muchas líneas del método render (), por lo que ahora existe la posibilidad de que algún día los métodos difieran. Y cada vez que edita render (), ahora debe recordar corregir renderForAssertions ().





En mi opinión, es fundamentalmente incorrecto probar métodos especialmente diseñados para pruebas, en lugar de código real. Esto es una especie de tontería.





Encuentro que con este compromiso, mi marco favorito ha empeorado un poco :(








All Articles