{"id":18745677,"url":"https://github.com/eckinox/introduction-tests-unitaires","last_synced_at":"2025-11-23T13:30:20.710Z","repository":{"id":109753085,"uuid":"489111215","full_name":"eckinox/introduction-tests-unitaires","owner":"eckinox","description":"Un atelier d'introduction aux tests unitaires pour les développeurs PHP.","archived":false,"fork":false,"pushed_at":"2022-05-10T13:40:52.000Z","size":31,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-12-28T20:25:57.533Z","etag":null,"topics":["educational","php","testing","training-materials"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eckinox.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-05-05T20:05:21.000Z","updated_at":"2022-05-10T13:48:14.000Z","dependencies_parsed_at":"2023-06-26T00:09:05.335Z","dependency_job_id":null,"html_url":"https://github.com/eckinox/introduction-tests-unitaires","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eckinox%2Fintroduction-tests-unitaires","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eckinox%2Fintroduction-tests-unitaires/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eckinox%2Fintroduction-tests-unitaires/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eckinox%2Fintroduction-tests-unitaires/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eckinox","download_url":"https://codeload.github.com/eckinox/introduction-tests-unitaires/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239627233,"owners_count":19670844,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["educational","php","testing","training-materials"],"created_at":"2024-11-07T16:19:09.046Z","updated_at":"2025-11-23T13:30:20.663Z","avatar_url":"https://github.com/eckinox.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Atelier d'introduction aux tests unitaires (en PHP)\n\n\u003e **📚 Avant de commencer...**  \n\u003e Ce repository est un atelier explicatif sur les tests automatisés, et plus \n\u003e spéciquemment sur les tests unitaires.\n\u003e \n\u003e Avant de commencer votre lecture, téléchargez ce repository sur votre ordinateur\n\u003e ou sur un serveur où PHP est installé, et installez les dépendances PHP en roulant \n\u003e la commande \n\u003e \n\u003e ```bash\n\u003e composer install\n\u003e ```\n\u003e \n\n---\n\n## Qu'est-ce qu'un test unitaire ?\n\nLes tests unitaires permettent de valider le bon fonctionnement d'une unité de code, \ncomme une classe, une fonction, ou un script.\n\nL'objectif d'un test est de valider que le code fonctionne tel que prévu, afin d'éviter\ndes bugs/problèmes lors de l'utilisation. Les tests permettent également de valider si \ndes changements au code sont backwards-compatible (aka: s'ils vont briser ou changer le \ncomportement du code existant).\n\n\n## Comment ça fonctionne ?\n\nEn résumé, un test consiste généralement en un exemple d'utilisation de l'unité de code,\ndans lequel sont parsemés des assertions.\n\n### Qu'est-ce qu'une assertion ?\n\nUne assertion, c'est simplement de valider que quelque chose est vrai. \n\nDans le cas de tests automatisés, les assertions comparent généralement une valeur retournée\npar le code à la valeur dont on s'attend à ce que le code retourne.\n\nVoici quelques types d'assertions communes:\n\n- `cette valeur` est vraie\n- `cette valeur` est fausse\n- `cette valeur` est un nombre\n- `cette valeur` est une chaine de caractères\n- `ce nombre` est plus grand que `X`\n- `ce nombre` est plus petit que `X`\n- `cet array` contient l'élément `X`\n\n### PHPUnit\n\nPour tirer avantage des tests, il faut qu'on rédige des tests, mais il faut également que\nces tests soient exécutés et qu'on puisse consulter les résultats! C'est là qu'entrent en\njeu les testing frameworks.\n\nDans le cas d'une codebase PHP, le framework le plus commun est [PHPUnit](https://phpunit.de/).\n\nSi vous êtes dans un projet Symfony, PHPUnit devrait déjà être installé et avoir une configuration\nde base pour votre projet. Sinon, vous pouvez l'installer et le configurer en suivant la \ndocumentation officielle.\n\n#### Cas de test dans PHPUnit\n\nAvec PHPUnit, on place généralement les tests dans un dossier `tests` à la racine de votre projet.\n\nUne bonne pratique est généralement de séparer les tests par type dans ce dossier. Il y a plusieurs\nmanières différentes de faire cela, mais en prenant en compte que le projet risque d'éventuellement\navoir plusieurs types de tests, voici une suggestion de structure assez complète:\n\n```\ntests\n  Backend\n    Unit\n      \u003e your PHP unit tests here, with the same file structure as your codebase\n    Integration\n      \u003e your PHP integration tests here\n\n  Frontend\n    Unit\n      \u003e your JS unit tests here, with the same file structure as your codebase\n    Integration\n      \u003e your JS integration tests here\n\n  EndToEnd\n    \u003e your E2E tests here\n\n  fixtures\n    \u003e store any files needed for your tests here\n```\n\n### Exécuter les tests avec PHPUnit\n\nUne fois PHPUnit installé, configuré, et vos tests rédigés, vous pouvez exécuter vos tests en\nroulant PHPUnit.\n\nSi vous l'avez installé avec Composer, la commande devrait être ceci:\n\n```bash\n./vendor/bin/phpunit\n```\n\nPar défaut, PHPUnit va rouler les tests dans le dossier indiqué par votre configuration. Vous\npouvez spécifiez quel(s) test(s) rouler en lui donnant le path d'un dossier ou d'un fichier. \n\nEx.:\n\n```bash\n./vendor/bin/phpunit tests/Unit/Validator\n```\n\nou:\n\n```bash\n./vendor/bin/phpunit tests/Unit/Validator/PhoneNumberValidatorTest.php\n```\n\nou encore:\n\n```bash\n./vendor/bin/phpunit tests/Unit/*\n```\n\n\n---\n\n## 📚✨ Exercice #1 ✨📚\n📚 À ce point dans l'atelier, vous pouvez passer à [l'exercice pratique #1](docs/exercice-1.md).  \n📚 Vous pourrez continuer la lecture/formation après cet exercice.  \n📚 Une fois que vous aurez terminé, [consultez une solution suggérée](./solutions/README.md).\n\n---\n\n\n## Fixtures\n\nIl est possible que vous ayez besoin de fichiers ou de données quelconques pour faire des tests.\n\nVous pourriez générer des données aléatoirement, mais cela ferait en sorte que votre test\nserait différent d'une exécution à l'autre. Et ça, on veut pas ça.\n\nAfin de vous assurer que vous testez toujours la même chose, vous pouvez créer et ajouter\nà votre projet des fichiers de test. Vous pouvez également utilisez des librairies comme \n[Foundry](https://github.com/zenstruck/foundry) pour générer des objets de test facilement. \n\nCes fichiers et données dont la seule fonction sera d'être utilisés pour exécuter vos tests\ns'appellent des Fixtures. \n\n## Mocks \u0026 stubs\n\nDans certains cas, vous allez vouloir tester du code qui a des dépendances ou des liens \navec d'autres classes/services/APIs/etc. \n\nÉtant donné que le rôle d'un test unitaire est de tester une seule unité de code en isolation,\nvous devrez éliminer les interférences/intéractions avec ces autres services.\n\nPour ce faire, il est pratique commune de créer ce qu'on appelle des **mocks** et/ou des **stubs**.\n\nEn gros, les mocks et les stubs sont une fausse version d'un service que vous pouvez configurer \nafin qu'il fonctionne comme vous le désirez.\n\n### Stub\nLes stubs permettent de simuler les intéractions avec des services réels tout en assurant que \nles valeurs retournées sont prévisibles et constantes.\n\nPar exemple, si vous avez une classe qui a comme dépendance un service `GoogleApi`, dont la méthode \n`search(string $searchTerms)` fait une recherche sur l'API de Google et vous retourne les résultats, \nvous pourriez créer un stub du service `GoogleApi` qui retourne toujours le même résultat lorsqu'on \nappelle sa méthode `search()`. \n\nAinsi, votre test ne dépend plus de l'API externe de Google: vous testez seulement le comportement\nde votre application. \n\nC'est donc plus rapide et plus stable. \n\n### Mock\nLes **mocks** fonctionnent essentiellement de la même manière que les stubs, mais ils permettent\négalement de faire des assertions sur les intéractions avec la classe/méthode qui est mockée. \n\nDans le même exemple du `GoogleApi`, vous pourriez créez un mock au lieu d'un stub afin de valider \nsi la méthode `GoogleApi::search()` est belle et bien appelée une fois (pas plus, pas moins) par \nvotre service.\n\n### Comment créer des mocks et des stubs\nIl y a plusieurs manières de créer des mocks et des stubs. \nLes plus communes pour les tests unitaires en PHP sont:\n\n- D'utiliser [documentation sur les mock \u0026 stubs de PHPUnit](https://phpunit.readthedocs.io/en/9.5/test-doubles.html).\n- D'utiliser une librairie / un framework de mock/stub alternatif comme [Mockery](https://github.com/mockery/mockery).\n\n### Le point négatif des mocks/stubs\nLes mocks/stubs ont deux problèmes principaux: \n\n- Créer des mocks/stubs peut être long.\n- Si le service externe que vous avez mocké/stubbé change, vos tests unitaires va continuer de rouler sans problème, \n  alors qu'en réalité votre application pourrait être brisée.\n\nLe 2e point est une des principales raisons pour lesquelles les tests unitaires ne donnent\npas aussi confiance que des tests E2E. \n\nIl faut donc garder en tête que plus on crée de mocks/stubs, moins nos tests réflètent la réalité,\net donc moins ils devraient nous donner confiance en notre application.\n\nÇa peut donc valoir la peine de créer des tests d'intégrations ou des tests E2E au lieu de \ndes tests unitaires qui dépendent beaucoup sur des stubs/mocks.\n\n\n\n---\n\n## 📚✨ Exercice #2 ✨📚\n📚 À ce point dans l'atelier, vous pouvez passer à [l'exercice pratique #2](docs/exercice-2.md).  \n📚 Vous pourrez continuer la lecture/formation après cet exercice.\n📚 Une fois que vous aurez terminé, [consultez une solution suggérée](./solutions/README.md).\n\n---\n\n\n## Qu'est-ce que je dois tester? À quel point mes tests doivent-ils être complets?\n\nDans un monde idéal, les tests couvriraient tous les scénarios imagineables. Pour ce faire,\non devrait créer plusieurs tests qui simuleraient chaqu'un de ces scénarios.\n\nDans un monde plus réaliste dans lequel le développement est limité par multiples contraintes\ntels que le temps et les budgets, l'objectif est différent: vos tests devraient couvrir assez \nde scénarios pour vous rendre confiant.e.s que si tous les tests passent, le logiciel \nfonctionnera bien comme prévu.\n\n\n## Les différents types de tests\n\nVoici un aperçu rapide des différents types de tests automatisés les plus communs:\n\n- **Tests statiques**: vérifient si votre code est valide (ex.: PHPMD, PHPStan, eslint, etc.).\n- **Tests unitaires**: vérifient si vos classes/méthodes fonctionnent comme prévu individuellement.\n- **Tests d'intégration**: vérifient si vos classes et services fonctionnent comme prévu ensemble.\n- **Tests end-to-end (E2E)**: vérifient si le logiciel fonctionne comme prévu du point de vue d'un utilisateur.\n\nChaque type de test a ses avantages et désavantages, et chacun a sa place. Une même application\nutilisera généralement tous ces types de tests afin de valider le bon fonctionnement à différents \nniveaux.\n\n### Pros \u0026 cons: tests unitaires et statiques\nLes tests statiques et unitaires sont très rapides, mais ne font que valider chaque bout code\nindividuellement. Ils ne peuvent donc pas vous donner confiance en votre application entière.\n\n### Pros \u0026 cons: tests d'intégration\nLes tests d'intégrations vous permettent de valider le bon fonctionnement de plusieurs systèmes\nqui travaillent ensembles. \n\nPar exemple, un test d'intégration pourrait simuler une requête HTTP envoyée à un controller \n(qui lui traite la requête en passant par différents services) et valider que la réponse du \ncontroller correspond bien à ce à quoi on s'attend. \n\nUn test d'intégration est un peu plus long à rédiger et à exécuter qu'un test unitaire, mais \ncela vous donne un plus haut niveau de confiance puisque ça simule un comportement semblable \nà celui d'un vrai utilisateur.\n\n### Pros \u0026 cons: tests E2E\nLes tests E2E vous permettent de tester le bon fonctionnement de votre application du point de \nvue de l'utilisateur. \n\nDans un test E2E, vous controllez un vrai navigateur; vous naviguez et vous intéragissez avec \nl'application en cliquant sur des liens et des boutons exactement comme un utilisateur le ferait. \n\nCes tests sont généralement plus long à rédiger et à exécuter que tous les autres types, \nmais ils vous offrent un niveau de confiance beaucoup plus élevés puisqu'ils vous permettent \nde tester tout votre application comme si un humain le faisait manuellement. Vous ne testez donc \nplus le code: vous testez réellement vos user stories.\n\n\n## Littérature additionnelle suggérée\n- [Write tests. Not too many. Mostly integration.](https://kentcdodds.com/blog/write-tests) (article par Kent C. Dodds)\n- [How to know what to test](https://kentcdodds.com/blog/how-to-know-what-to-test) (article par Kent C. Dodds)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feckinox%2Fintroduction-tests-unitaires","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feckinox%2Fintroduction-tests-unitaires","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feckinox%2Fintroduction-tests-unitaires/lists"}