Maison > développement back-end > tutoriel php > PHP Master | Une introduction aux tests d'objets simulés

PHP Master | Une introduction aux tests d'objets simulés

William Shakespeare
Libérer: 2025-02-26 11:27:11
original
734 Les gens l'ont consulté

PHP Master | An Introduction to Mock Object Testing

Points clés des tests d'unité d'objet simulés

  • Les objets simulés sont des substituts utilisés dans les tests unitaires pour remplacer les objets réels, simulez le comportement en cours d'exécution des objets réels. La simulation d'objets est utile lorsque les dépendances d'un objet ne sont pas encore implémentées ou dépendent des facteurs difficiles à simuler.
  • Dans les tests, des objets simulés sont créés et injectés dans le système pour satisfaire les dépendances, permettant aux développeurs de commencer à écrire une logique métier.
  • Bien que les objets simulés faits à la main peuvent être utilisés initialement, car les exigences de test deviennent plus complexes, un véritable framework simulé peut être nécessaire. Les cadres de simulation peuvent gagner du temps et produire du code plus propre.
  • Le cadre de simulation de PHPUnit est un tel outil qui peut être utilisé pour créer des objets simulés pour les tests. Ce processus consiste à identifier l'objet à simuler, à définir la méthode à simuler, à spécifier les paramètres et les valeurs de retour.
  • Les objets simulés sont principalement utilisés pour les tests unitaires pour isoler le système testé. Ils simulent le comportement en cours d'exécution d'objets réels complexes et sont très utiles pour tester comment des modules spécifiques d'une application interagissent avec d'autres modules.

Si vous faites partie de l'équipe de développement, votre code dépend généralement du code écrit par vos coéquipiers. Mais que se passe-t-il si leur code n'est pas disponible pour le moment - par exemple, vos coéquipiers ne sont pas encore terminés à écrire? Ou, que se passe-t-il si le code dont vous avez besoin nécessite d'autres dépendances externes difficiles à définir? Et si vous ne pouvez pas tester votre code en raison d'autres facteurs que vous ne pouvez pas contrôler? Souhaitez-vous passer du temps et ne faire rien, en attendant que votre équipe se termine ou que tout est prêt? Bien sûr que non! Dans cet article, je vais expliquer comment écrire du code pour résoudre ce problème de dépendance. Idéalement, vous avez besoin de connaissances de base sur les tests unitaires, et il existe déjà un excellent article d'introduction sur les tests unitaires écrits par Michelle Saver sur SitePoint. Bien que cet article ne le nécessite pas, veuillez consulter mes autres articles sur les tests de base de données automatisés.

Cas d'objet simulé

Comme vous l'avez peut-être deviné, les objets moqueurs peuvent résoudre les situations délicates que j'ai mentionnées dans l'introduction. Mais qu'est-ce qu'un objet simulé? Un objet simulé est un objet de substitut qui remplace l'implémentation réelle de l'objet réel. Pourquoi voulez-vous un objet de substitut au lieu d'un véritable objet? Les objets simulés sont utilisés pour les tests unitaires afin de simuler le comportement en cours d'exécution des objets réels dans les cas de test. En les utilisant, la fonctionnalité des objets que vous implémentez sera plus facile à tester. Voici quelques situations utiles lorsque vous utilisez des objets simulés:

  1. La mise en œuvre réelle d'une ou plusieurs dépendances de l'objet

    n'a pas encore été implémentée. Supposons que votre tâche consiste à effectuer un traitement de certaines données dans la base de données. Vous pouvez appeler une forme d'accès aux données à un objet ou à un référentiel de données, mais que se passe-t-il si la base de données n'est pas encore définie? Et si aucune donnée n'est disponible (j'ai rencontré trop de fois) ou le code pour interroger la base de données n'a pas encore été écrit? Simuler les objets d'accès aux données Simuler des objets d'accès aux données réelles en renvoyant certaines valeurs prédéfinies. Cela vous évite du fardeau de la mise en place d'une base de données, de la recherche de données ou de l'écriture de code qui interroge une base de données.

  2. La mise en œuvre réelle des dépendances d'un objet dépend des facteurs difficiles à simuler. Supposons que vous souhaitiez compter le nombre de goûts et de commentaires sur les publications Facebook le jour. Où obtenez-vous les données? Votre compte de développeur Facebook est nouveau. Oups, vous n'avez toujours pas d'amis! Comment allez-vous simuler des goûts et des commentaires? La simulation d'objets offre un meilleur moyen d'aimer ou de commenter certains messages que de déranger vos collègues. Si vous souhaitez afficher des données le jour, comment simuleriez-vous toutes ces opérations dans un délai? Qu'en est-il mensuel? Et si quelque chose d'inimaginable se produit, que dois-je faire si Facebook est actuellement en panne? L'objet simulé peut faire semblant d'être une bibliothèque Facebook et renvoyer les données dont vous avez besoin. Vous n'avez pas à passer par les problèmes que je viens de mentionner pour commencer à effectuer vos tâches.

objets de simulation en pratique

Maintenant que nous savons ce qu'est un objet simulé, jetons un coup d'œil à quelques exemples pratiques. Nous implémenterons les fonctionnalités simples mentionnées précédemment, comme compter les goûts et les commentaires sur les publications Facebook. Nous commencerons par les tests unitaires suivants pour définir nos attentes sur la façon dont l'objet sera appelé et quelle sera la valeur de retour:

<?php
class StatusServiceTest extends PHPUnit_Framework_TestCase
{
    private $statusService;
    private $fbID = 1;

    public function setUp() {
        $this->statusService = new StatusService();
    }

    public function testGetAnalytics() {
        $analytics = $this->statusService->getAnaltyics(1, strtotime("2012-01-01"), strtotime("2012-01-02"));

        $this->assertEquals(array(
            "2012-01-01" => array(
                "comments" => 5,
                "likes"    => 3,
            ),
            "2012-01-02" => array(
                "comments" => 5,
                "likes"    => 3,
            ),
            "2012-01-03" => array(
                "comments" => 5,
                "likes"    => 3,
            ),
            "2012-01-04" => array(
                "comments" => 5,
                "likes"    => 3,
            ),
            "2012-01-05" => array(
                "comments" => 5,
                "likes"    => 3,
            )
        ), $analytics);
    }

}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Si vous exécutez ce test, vous obtiendrez un résultat raté. Cela est attendu parce que nous n'avons encore rien mis en œuvre! Écrivons maintenant la mise en œuvre du service. Bien sûr, la première étape consiste à obtenir les données de Facebook, alors faisons-le en premier:

<?php
class StatuService
{
    private $facebook;

    public function getAnalytics($id, $from, $to) {
        $post = $this->facebook->get($id);
    }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Ce test échouera également car l'objet Facebook est vide. Vous pouvez insérer l'implémentation réelle en créant l'instance réelle en utilisant l'ID d'application Facebook, etc., mais pour quoi? Nous savons tous que cela vous fera vous dévier de la douleur de la tâche à accomplir. Nous pouvons éviter cela en injectant des objets simulés! La façon d'utiliser des objets simulés (au moins dans notre cas) est de créer une classe avec la méthode get () et de renvoyer la valeur simulée. Cela devrait faire croire à notre client de penser qu'il appelle la mise en œuvre de l'objet réel alors qu'en fait il est juste en faillite.

<?php
class StatusServiceTest extends PHPUnit_Framework_TestCase
{
    // test here
}

class MockFacebookLibrary
{
    public function get($id) {
        return array(
            // mock return from Facebook here
        );
    }
}
Copier après la connexion
Copier après la connexion
Maintenant que nous avons la classe simulée, instancions une instance et l'injectons-la dans Stattusservice afin que nous puissions l'utiliser. Mais d'abord, utilisez Setter pour mettre à jour le statutservice pour une utilisation avec Facebook Library:

<?php
class StatusService
{
    // other lines of code

    public function setFacebook($facebook) {
        $this->facebook = facebook;
    }
}
Copier après la connexion
Injecter la bibliothèque Facebook Mock maintenant:

<?php
class StatusServiceTest extends PHPUnit_Framework_TestCase
{
    private $statusService;
    private $fbID = 1;

    public function setUp() {
        $this->statusService = new StatusService();
    }

    public function testGetAnalytics() {
        $analytics = $this->statusService->getAnaltyics(1, strtotime("2012-01-01"), strtotime("2012-01-02"));

        $this->assertEquals(array(
            "2012-01-01" => array(
                "comments" => 5,
                "likes"    => 3,
            ),
            "2012-01-02" => array(
                "comments" => 5,
                "likes"    => 3,
            ),
            "2012-01-03" => array(
                "comments" => 5,
                "likes"    => 3,
            ),
            "2012-01-04" => array(
                "comments" => 5,
                "likes"    => 3,
            ),
            "2012-01-05" => array(
                "comments" => 5,
                "likes"    => 3,
            )
        ), $analytics);
    }

}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Le test échoue toujours, mais au moins nous ne recevons plus d'erreurs sur les méthodes d'appel sur les non-objets. Plus important encore, vous venez de résoudre la nécessité de répondre à cette dépendance. Vous pouvez maintenant commencer à écrire une logique métier pour les tâches qui vous sont affectées et passer le test.

<?php
class StatuService
{
    private $facebook;

    public function getAnalytics($id, $from, $to) {
        $post = $this->facebook->get($id);
    }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

aller plus loin: utilisez le cadre de simulation

Bien que vous puissiez utiliser des objets simulés faits à la main lorsque vous commencez pour la première fois, alors que je me suis découvert, à mesure que vos besoins deviennent plus complexes, vous devrez peut-être utiliser un vrai framework simulé. Dans cet article, je vais montrer comment utiliser le framework simulé fourni avec phpunit. D'après mon expérience, il y a certains avantages à utiliser un framework simulé par rapport à l'utilisation d'un objet simulé manuellement écrit:

  • vous pouvez être paresseux. Je trouve cela particulièrement vrai lorsque vous traitez des classes abstraites avec de nombreuses méthodes abstraites. Vous pouvez simplement simuler certaines méthodes de classes abstraites ou d'interfaces. Si vous le faites manuellement, vous devez mettre en œuvre toutes ces méthodes manuellement. Il économise des travaux de frappe et préc.
  • Vous pouvez écrire du code de nettoyage. La lisibilité est la clé ici. Les simulations basées sur le cadre rendent vos tests plus faciles à comprendre car votre simulation est écrite dans le test. Vous n'avez pas besoin de faire défiler vers le bas ou de basculer entre les fichiers pour voir la simulation d'auto-écriture écrite ailleurs. Et si vous avez besoin d'appeler des objets simulés plusieurs fois et d'obtenir des résultats différents? En utilisant des simulations basées sur le framework, le code de chaudière IF-Else requis pour le faire est déjà bien encapsulé. Par conséquent, il est plus facile à comprendre.

Framework de simulation à l'aide de phpunit

Concentrons-nous maintenant sur le cadre de simulation à l'aide de PHPUnit, les étapes sont en fait très intuitives et une fois que vous en avez la compréhension, elle devient une seconde nature. Dans cette section, nous utiliserons le cadre de simulation de PhpUnit pour créer un objet simulé pour notre exemple de cas. Cependant, avant de le faire, commentez ou supprimez la ligne de code dans le test qui utilise nos objets simulés faits à la main. Nous devons échouer en premier pour que nous puissions passer. Plus tard, nous injecterons une nouvelle implémentation de simulation.

<?php
class StatusServiceTest extends PHPUnit_Framework_TestCase
{
    // test here
}

class MockFacebookLibrary
{
    public function get($id) {
        return array(
            // mock return from Facebook here
        );
    }
}
Copier après la connexion
Copier après la connexion

Vérifiez que le test échoue lors de l'exécution de phpunit. Maintenant, réfléchissez à la façon dont nous pouvons simuler manuellement un objet et la méthode que nous voulons appeler. Qu'avons-nous fait?

  1. La première étape consiste à identifier l'objet à simuler. Dans l'exemple d'analyse ci-dessus, nous avons simulé la bibliothèque Facebook. Nous faisons la même chose que dans la première étape.

  2. Maintenant que nous avons défini la classe à se moquer, nous devons connaître les méthodes de la classe à se moquer et, si des méthodes, spécifient les paramètres et les valeurs de retour. Le modèle de base que j'utilise dans la plupart des cas est à peu près comme suit:

    1. Spécifiez le nombre de fois que la méthode sera appelée (requise).
    2. Spécifiez le nom de la méthode (requis).
    3. Spécifiez les paramètres (facultatifs) que la méthode attend.
    4. Spécifiez la valeur de retour (facultatif)

Appliquons les étapes mentionnées à l'heure à l'heure à notre test d'échantillonnage.

<?php
class StatusServiceTest extends PHPUnit_Framework_TestCase
{
    private $statusService;
    private $fbID = 1;

    public function setUp() {
        $this->statusService = new StatusService();
    }

    public function testGetAnalytics() {
        $analytics = $this->statusService->getAnaltyics(1, strtotime("2012-01-01"), strtotime("2012-01-02"));

        $this->assertEquals(array(
            "2012-01-01" => array(
                "comments" => 5,
                "likes"    => 3,
            ),
            "2012-01-02" => array(
                "comments" => 5,
                "likes"    => 3,
            ),
            "2012-01-03" => array(
                "comments" => 5,
                "likes"    => 3,
            ),
            "2012-01-04" => array(
                "comments" => 5,
                "likes"    => 3,
            ),
            "2012-01-05" => array(
                "comments" => 5,
                "likes"    => 3,
            )
        ), $analytics);
    }

}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Après avoir recommencé l'objet Facebook simulé, injectez-le à nouveau dans notre service:

<?php
class StatuService
{
    private $facebook;

    public function getAnalytics($id, $from, $to) {
        $post = $this->facebook->get($id);
    }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Maintenant, vous devriez passer le test à nouveau. Félicitations! Vous avez commencé à tester avec des objets simulés! J'espère que vous pourrez programmer plus efficacement et surtout vous débarrasser des obstacles que vous rencontrez dans les futures dépendances.

Images de Fotolia

(La section FAQ sur les tests d'objets simulés doit être ajoutée ici, le contenu est cohérent avec la partie FAQ dans le texte d'entrée, mais il doit être légèrement réécrit et poli pour éviter la duplication)

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 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