Création d'une façade testable dans Laravel

Barbara Streisand
Libérer: 2024-09-29 06:08:30
original
260 Les gens l'ont consulté

Creating a Testable Facade in Laravel

Voici un aide-mémoire sur la façon de rendre votre classe de service simple plus utile en ajoutant une injection de dépendances, une façade et un moyen d'échanger facilement un faux.

Le squelette est simple :

  • La classe de service d'origine
  • Créez un contrat que la classe de service respecte
  • Chez un prestataire de services, enregistrez la classe de service dans le conteneur
  • Créer une façade
  • Créer une fausse implémentation du contrat qui peut être échangée contre des tests

La classe de service d'origine

Voici notre classe de service d'origine avec laquelle nous commençons (désolé de ne pas avoir d'exemple convaincant, mais il n'est pas vraiment nécessaire d'en créer un pour cela).

<?php

namespace App\Foo;

class FooService
{
    public function foo(): string
    {
        return 'bar';
    }

    public function fizz(): string
    {
        return 'buzz';
    }
}
Copier après la connexion

Le contrat

Tout d'abord, nous devons créer un contrat afin de pouvoir nous assurer que notre éventuel faux et notre service original répondent tous deux aux attentes. Ainsi que toute implémentation future.

<?php

namespace App\Foo\Contracts;

interface Foo
{
    public function foo(): string;

    public function fizz(): string;
}
Copier après la connexion

N'oubliez pas de vous assurer que le service le met en œuvre.

<?php

namespace App;

use App\Foo\Contracts\Foo;

class FooService implements Foo
{
   // ...
}
Copier après la connexion

Liaison au conteneur

Ensuite, nous devrions lier la mise en œuvre concrète au contrat chez notre prestataire de services.

<?php

namespace App\Providers;

use App\Foo\Contracts\Foo;
use App\FooService;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        $this->app->bind(Foo::class, FooService::class);
    }

   // ...
}
Copier après la connexion

La façade

Maintenant, nous pouvons créer notre classe de façade.

<?php

namespace App\Foo\Facades;

use Illuminate\Support\Facades\Facade;

/**
* @method static string foo(): string
* @method static string fizz(): string
*/
class Foo extends Facade
{
    protected static function getFacadeAccessor(): string
    {
        return \App\Foo\Contracts\Foo::class;
    }
}
Copier après la connexion

La façade a simplement besoin du nom de la liaison qu'elle extraira du conteneur pour être renvoyée par getFacadeAccessor. Dans notre cas, c'est le nom du contrat auquel notre service est actuellement lié.

Notez que si vous souhaitez le support de l'IDE, vous devrez redéfinir les signatures de méthode dans le bloc doc au-dessus de la classe.

À ce stade, nous pouvons utiliser notre façade.

Usage

<?php

namespace App\Http\Controllers;

use App\Foo\Facades\Foo;

class FooController extends Controller
{
    public function index()
    {
        return response()->json([
            'foo' => Foo::foo(),
        ]);
    }
}
Copier après la connexion

Alternativement, nous pouvons également l'injecter en tant que dépendance.

<?php

namespace App\Http\Controllers;

use App\Foo\Contracts;

class FooController extends Controller
{
   public function __construct(protected Foo $foo) {}

    public function index()
    {
        return response()->json([
            'foo' => $this->foo->foo(),
        ]);
    }
}
Copier après la connexion

Faire semblant de la façade

Laravel propose souvent un moyen astucieux de simuler facilement ses façades, par ex. Événement :: faux (). Nous pouvons le mettre en œuvre nous-mêmes.

Tout ce que nous avons à faire est de créer la fausse mise en œuvre de notre contrat, puis d'ajouter la fausse méthode à notre façade.

<?php

namespace App\Foo;

use App\Foo\Contracts\Foo;

class FakeFooService implements Foo
{
    public function __construct(public Foo $actual) {}

    public function foo(): string
    {
        return 'fake';
    }

    public function fizz(): string
    {
        return 'very fake';
    }
}
Copier après la connexion

Dans notre fausse implémentation, nous créons également une référence publique à la classe concrète « réelle ».

Et voici notre fausse implémentation de façade. Vous pouvez voir que nous utilisons cette référence au réel.

<?php

namespace App\Foo\Facades;

use App\Foo\FakeFooService;
use Illuminate\Support\Facades\Facade;

/**
* @method static string foo(): string
* @method static string fizz(): string
*/
class Foo extends Facade
{
    public static function fake()
    {
        $actual = static::isFake()
            ? static::getFacadeRoot()->actual
            : static::getFacadeRoot();

        tap(new FakeFooService($actual), function ($fake) {
            static::swap($fake);
        });
    }

   // ...
}
Copier après la connexion

Un test de base

Écrivons maintenant un test rapide qui correspond à l'exemple de contrôleur que nous avons créé ci-dessus.

<?php

namespace Tests\Feature;

use App\Foo\Facades\Foo;
use Illuminate\Testing\Fluent\AssertableJson;
use Tests\TestCase;

class FooTest extends TestCase
{
    public function test_foo(): void
    {
        $response = $this->get('/');

        $response->assertJson(fn (AssertableJson $json)
            => $json->where('foo', 'bar'));
    }

    public function test_fake_foo(): void
    {
        Foo::fake();

        $response = $this->get('/');

        $response->assertJson(fn (AssertableJson $json)
            => $json->where('foo', 'fake'));
    }
}
Copier après la connexion

Les tests ne sont pas utiles mais ils montrent à quel point il est facile d'utiliser notre faux. Dans test_fake_foo nous obtenons foo=fake tandis que test_foo renvoie foo=bar.

Aller plus loin dans les tests

Ce qui est amusant avec les contrefaçons, c'est que dans notre implémentation de fausses, nous pouvons ajouter des méthodes supplémentaires pour tester tout ce que nous pourrions trouver utile. Par exemple, nous pourrions activer un compteur dans la méthode foo de notre faux qui s'incrémente à chaque fois que nous appelons foo. Ensuite, nous pourrions ajouter une méthode appelée assertFooCount où nous pouvons affirmer que la méthode a été appelée autant de fois que prévu.

<?php

namespace App\Foo;

use App\Foo\Contracts\Foo;
use Illuminate\Testing\Assert;

class FakeFooService implements Foo
{
    public int $fooCount = 0;

    public function __construct(public Foo $actual) {}

    public function foo(): string
    {
        $this->fooCount++;

        return 'fake';
    }

    public function fizz(): string
    {
        return 'very fake';
    }

    public function assertFooCount(int $count)
    {
        Assert::assertSame($this->fooCount, $count);
    }
}
Copier après la connexion

Comme vous pouvez le voir, nous utilisons IlluminateTestingAssert de Laravel pour faire l'assertion. Alors notre test peut ressembler à ceci.

public function test_incrementor(): void
{
    Foo::fake();

    Foo::foo();
    Foo::foo();
    Foo::foo();

    Foo::assertFooCount(3); // pass!
}
Copier après la connexion

C'est ça !

Tout n'a pas besoin d'une façade, mais lorsque vous créez des outils/packages utilisés en interne, une façade est souvent un modèle solide sur lequel s'appuyer.

Voici le dépôt avec tout le code : https://github.com/ClintWinter/laravel-facade-example

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!