Maison  >  Article  >  développement back-end  >  Concentrer vos tests sur le domaine. Un exemple PHPUnit

Concentrer vos tests sur le domaine. Un exemple PHPUnit

DDD
DDDoriginal
2024-10-05 06:07:30605parcourir

Introduction

Souvent, les développeurs essaient de tester 100 % (ou presque 100 %) de leur code. Apparemment, c'est l'objectif que chaque équipe devrait atteindre pour ses projets mais, de mon point de vue, une seule partie de l'ensemble du code devrait être entièrement testée : votre domaine.

Le domaine est, essentiellement, la partie de votre code qui définit ce que fait réellement le projet. Par exemple, lorsque vous conservez une entité dans la base de données, votre domaine n'est pas chargé de la conserver dans la base de données, mais de s'assurer que les données conservées ont un sens selon votre modèle économique. Il est possible que lorsque vous enregistrez vos données dans la base de données, vous utilisiez une bibliothèque externe comme PHP Doctrine. Cette bibliothèque est déjà entièrement testée, il n'est pas nécessaire de tester ce qu'elle fait. Si vous transmettez à Doctrine les données correctes, elles seront enregistrées dans la base de données sans problème.

L'exemple présenté dans les sections suivantes n'essaie pas de montrer comment fonctionne le Domain Driven Design, il existe de nombreux articles qui l'expliquent très bien. Je vais essayer de montrer comment avoir votre domaine bien défini et découplé peut vous aider à tester facilement et en vous concentrant sur ce que fait votre application.

L'exemple est construit sur un environnement Symfony et en utilisant la bibliothèque PHPUnit, mais l'idée est valable pour n'importe quel langage ou framework.

Le code à tester

Imaginons que notre application se connecte à une API externe qui renvoie des données sur la probabilité de pluie pour une date spécifiée. Les données renvoyées ressemblent à ceci :


{
   "date" : "2022-12-01",
   "rain_probability" : 0.75
}


Maintenant, nous devons prendre ces données et les classer selon cette cartographie :

  • rain_probability < 0.40 : FAIBLE
  • rain_probability ≥ 0,40 && rain_probability < 0,75 : MOYEN
  • probabilité_pluie ≥ 0,75 : ÉLEVÉE

et enregistrez le résultat sur une table de base de données décrite par l'entité suivante :


#[ORM\Entity(repositoryClass: RainMeasure::class)]
class RainMeasure {

    #[ORM\Column]
    private string $date;

    #[ORM\Column]
    private float $probability;

    #[ORM\Column(length: 10)]
    private string $label;

    // Getters and setters
    // .......
}


Créons un gestionnaire qui récupère les données de l'API externe, définit l'étiquette en fonction de la probabilité de pluie et l'enregistre dans la base de données.


class RainMeassureHandler {
    private EntityManagerInterface $em;

    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }

    public function saveMeasure(array $measureData): void
    {
        if($measureData['rain_probability'] < 0.40){
            $label = 'LOW';
        }
        elseif ($measureData['rain_probability'] >= 0.40 && $measureData['rain_probability'] < 0.75){
            $label = 'MEDIUM';
        }
        else{
            $label = 'HIGH';
        }

        $rainMeasure = new RainMeassure();
        $rainMeasure->setDate($measureData['date']);
        $rainMeasure->setProbability($measureData['rain_probability']);
        $rainMeasure->setLabel($label);

        $this->em->persist($rainMeasure);
        $this->em->flush();
    }
}




<p>Si nous essayons de créer un test pour le gestionnaire ci-dessus, nous constaterons que nous devrons injecter l'<strong>EntityManagerInterface</strong> puisque le comportement que nous voulons tester (définir une étiquette en fonction de la valeur de probabilité) est couplé dans le même gestionnaire qui enregistre le résultat dans la base de données. Nous pourrions essayer de charger l'<strong>EntityManagerInterface</strong> à l'aide de mocks et de stubs mais est-ce nécessaire ?. Évidemment non. Comme dit précédemment, nous devrions essayer de nous concentrer sur le test du comportement qui appartient à notre domaine, c'est-à-dire obtenir la bonne étiquette en fonction de la probabilité de pluie.</p>

<h2>
  
  
  Comportement de découplage que nous voulons tester
</h2>

<p>Afin de simplifier notre test, nous allons déplacer le comportement que nous souhaitons tester vers une autre classe :</p>

<pre class="brush:php;toolbar:false">

class RainMeasureLabelHandler 
{
    public function getLabelFromProbability(float $prob): string
    {
        if($prob < 0.40){
            $label = 'LOW';
        }
        elseif ($prob >= 0.40 && $prob < 0.75){
            $label = 'MEDIUM';
        }
        else{
            $label = 'HIGH';
        }

        return $label;
    }
}


Et maintenant, notre RainMeassureHandler ressemblera à ceci :


class RainMeasureHandler 
{
    private EntityManagerInterface $em;

    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }

    public function saveMeasure(array $measureData): void
    {
        $rainMeasureLabelHandler = new RainMeasureLabelHandler();
        $label = $rainMeasureLabelHandler->getLabelFromProbability($measureData['rain_probability']);

        $rainMeasure = new RainMeasure();
        $rainMeasure->setDate($measureData['date']);
        $rainMeasure->setProbability($measureData['rain_probability']);
        $rainMeasure->setLabel($label);

        $this->em->persist($rainMeasure);
        $this->em->flush();
    }
}


Nous pouvons maintenant nous concentrer sur le test de notre RainMeasureLabelHandler qui ferait partie de notre domaine et n'aurait aucune dépendance vis-à-vis des couches externes. Le tester serait aussi simple que indiqué :

Focusing your tests on the domain. A PHPUnit example

Conclusion

Je voudrais dire que d’autres types de tests seraient également utiles. Peut-être avons-nous une API et souhaitons-nous tester les entrées et les sorties avec un environnement de test qui comprend une base de données et d'autres ressources dont nous pourrions avoir besoin. Mais n'oubliez pas de faire découpler votre domaine et de le tester entièrement.

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!

Déclaration:
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