Einführung
Laravel ist ein cooles PHP-Framework, das wir im Unternehmen ständig verwenden. Aber wie Sie wissen, ist nichts auf der Welt perfekt, Sie können immer Verbesserungen vorschlagen.
Vor einigen Wochen habe ich versucht, eine kleine Verbesserung im Laravel-Testbereich vorzunehmen, und zwei Pull-Anfragen ( Nr. 1 und Nr. 2 ) geöffnet . Beide Pull-Anfragen wurden vom Autor des Frameworks, Taylor, abgelehnt, aber am selben Tag veröffentlichte er seine eigene Implementierung derselben Funktionalität, mit der er sich sogar auf Twitter rühmte. Und, oh Götter, die Erkenntnis ist schrecklich!
Kontext
Wir bevorzugen Integrationstests allein, da Sie so ein ausgewogenes Verhältnis zwischen den Kosten für automatisierte Tests und dem Vertrauen in Ihre Bereitstellungen erzielen können. Oft tun wir in unseren Integrationstests etwas im Namen des Benutzers und möchten dann sicherstellen, dass der Benutzer irgendwann einen Brief erhalten hat. Zu diesem Zweck implementiert Laravel die Standardmethode:
<?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();
, , . , , , .
Unser Ziel war es, die Kampfcode-Methoden render () und send () zu testen. Wir haben eine neu erstellte neue Methode getestet, die in der Praxis niemand anwenden wird.
Schauen wir uns diese Methode an:
<?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, keine Methode, sondern ein Monster!
Es ist nicht nur sehr schwer zu lesen, es wiederholt auch viele Zeilen der render () -Methode, sodass jetzt die Möglichkeit besteht, dass die Methoden eines Tages voneinander abweichen. Und jedes Mal, wenn Sie render () bearbeiten, müssen Sie daran denken, renderForAssertions () zu korrigieren.
Meiner Meinung nach ist es grundsätzlich falsch, anstelle von echtem Code speziell für Tests entwickelte Testmethoden zu verwenden. Das ist eine Art Unsinn.
Ich finde, dass mit diesem Commit mein Lieblings-Framework etwas schlechter geworden ist :(