Tester les contrôleurs n'est pas la chose la plus facile au monde. Eh bien, permettez-moi de reformuler ceci: les tester est un jeu d'enfant; ce qui est difficile, du moins au début, c'est de déterminer quoi tester.
Un test de contrôleur doit-il vérifier le texte sur la page? Devrait-il toucher la base de données? Devrait-il s’assurer que les variables existent dans la vue? S'il s'agit de votre premier tour de foin, ces choses peuvent être déroutantes! Laisse moi aider.
Les tests du contrôleur doivent vérifier les réponses, s'assurer que les bonnes méthodes d'accès à la base de données sont déclenchées et affirmer que les variables d'instance appropriées sont envoyées à la vue..
Le processus de test d'un contrôleur peut être divisé en trois parties.
Vue
).La meilleure façon d'apprendre ces choses est d'utiliser des exemples. Ici se trouve le "Bonjour le monde"des tests de contrôleurs à Laravel.
client-> requête ('GET', 'posts');
Laravel exploite une poignée de composants Symfony pour faciliter le processus de test des itinéraires et des vues, notamment HttpKernel, DomCrawler et BrowserKit. C’est pourquoi il est primordial que vos tests PHPUnit héritent de, pas PHPUnit \ _Framework \ _TestCase
, mais Cas de test
. Ne vous inquiétez pas, Laravel étend toujours l'ancien, mais cela aide à configurer l'application Laravel pour les tests et fournit une variété de méthodes d'assertion d'aide que vous êtes encouragés à utiliser. Plus à ce sujet sous peu.
Dans l'extrait de code ci-dessus, nous faisons un OBTENIR
demande à /des postes
, ou localhost: 8000 / posts
. En supposant que cette ligne soit ajoutée à une nouvelle installation de Laravel, Symfony lancera une NotFoundHttpException
. Si vous travaillez bien, essayez-le en exécutant phpunit
depuis la ligne de commande.
$ phpunit 1) PostsControllerTest :: testIndex Symfony \ Component \ HttpKernel \ Exception \ NotFoundHttpException:
Dans parler humain, cela se traduit essentiellement par "Hey, j'ai essayé d'appeler cette route, mais vous n'avez rien enregistré, imbécile!"
Comme vous pouvez l’imaginer, ce type de demande est assez courant au point qu’il est logique de fournir une méthode d’aide, telle que $ this-> call ()
. En fait, Laravel fait exactement cela! Cela signifie que l'exemple précédent peut être refactoré, comme suit:
# app / tests / controllers / PostsControllerTest.php fonction publique testIndex () $ this-> call ('GET', 'posts');
Bien que nous nous en tenions aux fonctionnalités de base de ce chapitre, dans mes projets personnels, je vais encore plus loin en permettant des méthodes telles que $ this-> get ()
, $ this-> post ()
, etc. Grâce à la surcharge PHP, cela ne nécessite que l’ajout d’une seule méthode, que vous pouvez ajouter à app / tests / TestCase.php
.
# app / tests / TestCase.php public function __call ($ method, $ args) if (in_array ($ method, ['get', 'post', 'put', 'patch', 'delete']))) return $ this-> call ($ method, $ args [0]); jeter une nouvelle BadMethodCallException;
Maintenant, vous êtes libre d'écrire $ this-> get ('posts')
et obtenir exactement le même résultat que les deux exemples précédents. Comme indiqué ci-dessus, cependant, restons fidèles à la fonctionnalité de base du framework pour des raisons de simplicité..
Pour réussir le test, il suffit de préparer le bon parcours.
Fonctionnement
phpunit
encore nous reviendrons au vert.
Assertions de Laravel
Un test que vous vous retrouvez en train d'écrire à plusieurs reprises est celui qui garantit qu'un contrôleur transmet une variable particulière à une vue. Par exemple, le
indice
méthode dePostsController
devrait passer un$ posts
variable à sa vue associée, non? De cette façon, la vue peut filtrer à travers tous les articles et les afficher sur la page. Ceci est un test important à écrire!Si c'est une tâche si commune, alors, encore une fois, ne serait-il pas logique que Laravel fournisse une affirmation d'assistance pour accomplir cette chose même? Bien sûr que ce serait. Et bien sûr, Laravel fait!
Illuminate \ Foundation \ Testing \ TestCase
comprend un certain nombre de méthodes qui réduiront considérablement la quantité de code nécessaire pour effectuer des assertions de base. Cette liste comprend:
assertViewHas
assertResponseOk
assertRedirectedTo
assertRedirectedToRoute
assertRedirectedToAction
assertSessionHas
assertSessionHasErrors
Les exemples suivants d'appels GET / posts
et vérifie que ses vues reçoivent la variable, $ posts
.
# app / tests / controllers / PostsControllerTest.php fonction publique testIndex () $ this-> call ('GET', 'posts'); $ this-> assertViewHas ('posts');
Pointe: En ce qui concerne le formatage, je préfère fournir un saut de ligne entre l'assertion d'un test et le code qui prépare la scène..
assertViewHas
est tout simplement un peu de sucre qui inspecte l'objet de réponse - qui est renvoyé de $ this-> call ()
- et vérifie que les données associées à la vue contiennent un des postes
variable.
Lors de l'inspection de l'objet de réponse, vous avez deux choix fondamentaux.
$ response-> getOriginalContent ()
: Récupère le contenu original ou le rendu Vue
. Vous pouvez éventuellement accéder à la original
propriété directement, plutôt que d'appeler le getContenuOriginal
méthode.$ response-> getContent ()
: Récupère la sortie rendue. Si un Vue
instance est renvoyée de la route, puis Obtenir du contenu()
sera égal à la sortie HTML. Cela peut être utile pour les vérifications DOM, telles que "la vue doit contenir cette chaîne."Supposons que le des postes
itinéraire comprend:
Devrions-nous courir
phpunit
, il va hurler avec un utile L'étape suivante message:1) PostsControllerTest :: testIndex Échec de l'affirmation qu'un tableau a la clé 'posts'.Pour le rendre vert, nous allons simplement chercher les messages et les passer à la vue.
# app / routes.php Route :: get ('posts', function () $ posts = Post :: all (); retourne View :: make ('posts.index', ['posts', $ posts]) ;);Une chose à garder à l’esprit est que, dans l’état actuel du code, il ne fait que garantir que la variable,
$ posts
, est passé à la vue. Il n'inspecte pas sa valeur. leassertViewHas
accepte éventuellement un deuxième argument pour vérifier la valeur de la variable, ainsi que son existence.# app / tests / controllers / PostsControllerTest.php fonction publique testIndex () $ this-> call ('GET', 'posts'); $ this-> assertViewHas ('posts', 'foo');Avec ce code modifié, la vue a une variable,
$ posts
, c'est égal àfoo
, le test échouera. Dans cette situation, cependant, il est probable que nous préférerions ne pas spécifier de valeur, mais plutôt déclarer que cette valeur est une instance de Laravel.Illuminate \ Database \ Eloquent \ Collection
classe. Comment pourrions-nous accomplir cela? PHPUnit fournit une aide utileassertInstanceOf
affirmation pour combler ce besoin même!# app / tests / controllers / PostsControllerTest.php fonction publique testIndex () $ response = $ this-> call ('GET', 'posts'); $ this-> assertViewHas ('posts'); // getData () renvoie tous les vars attachés à la réponse. $ posts = $ response-> original-> getData () ['posts']; $ this-> assertInstanceOf ('Illuminate \ Database \ Eloquent \ Collection', $ posts);Avec cette modification, nous avons déclaré que le contrôleur doit passer
$ posts
- une instance deIlluminate \ Database \ Eloquent \ Collection
- à la vue. Excellent.
Se moquer de la base de données
Il y a un problème criant avec nos tests jusqu'à présent. L'as-tu attrapé?
Pour chaque test, une requête SQL est en cours d'exécution sur la base de données. Bien que cela soit utile pour certains types de tests (acceptation, intégration), pour les tests de base des contrôleurs, cela ne fera que diminuer les performances..
J'ai percé cela plusieurs fois dans votre crâne à ce stade. Nous ne souhaitons pas tester la capacité d'Eloquent à extraire des enregistrements d'une base de données. Il a ses propres tests. Taylor sait que ça marche! Ne perdons pas de temps et de puissance de traitement en répétant ces mêmes tests.
Au lieu de cela, il est préférable de simuler la base de données et de simplement vérifier que les méthodes appropriées sont appelées avec les arguments corrects. Ou, en d'autres termes, nous voulons nous assurer que
Poste :: tous ()
ne tire jamais et frappe la base de données. Nous savons que cela fonctionne, donc il ne nécessite pas de test.Cette section dépendra beaucoup de la bibliothèque Mockery. Veuillez relire ce chapitre de mon livre, si vous ne le connaissez pas encore.
Refactoring requis
Malheureusement, jusqu'à présent, nous avons structuré le code de manière à rendre pratiquement impossible le test.
# app / routes.php Route :: get ('posts', function () // Aïe. Nous ne pouvons pas tester ceci! $ posts = Post :: all (); return View :: make ('posts. index ') -> avec (' posts ', $ posts););C’est précisément la raison pour laquelle il est considéré comme une mauvaise pratique d’intégrer des appels Eloquent à vos contrôleurs. Ne confondez pas les façades de Laravel, qui sont testables et peuvent être échangées avec des simulacres (
Queue :: shouldReceive ()
), avec vos modèles Eloquent. La solution consiste à injecter la couche base de données dans le contrôleur via le constructeur. Cela nécessite du refactoring.Attention: Stocker la logique dans les rappels de route est utile pour les petits projets et les API, mais rend les tests extrêmement difficiles. Pour les applications de toutes tailles, utilisez des contrôleurs.
Enregistrons une nouvelle ressource en remplaçant le
des postes
itinéraire avec:# app / routes.php Route :: resource ('posts', 'PostsController');… Et créez le contrôleur ingénieux nécessaire avec Artisan.
$ php artisan controller: rendre le contrôleur PostsController créé avec succès!Maintenant, plutôt que de faire référence à la
Poster
modéliser directement, nous l'injecterons dans le constructeur du contrôleur. Voici un exemple condensé qui omet toutes les méthodes reposantes, sauf celle que nous sommes actuellement intéressés à tester..post = $ post; fonction publique index () $ posts = $ this-> post-> all (); return View :: make ('posts.index') -> avec ('posts', $ posts);Notez que c’est une meilleure idée de dactylographier une interface plutôt que de faire référence au modèle Eloquent lui-même. Mais, une chose à la fois! Travaillons à cela.
C'est un moyen nettement meilleur de structurer le code. Comme le modèle est maintenant injecté, nous avons la possibilité de le remplacer par une version simulée à des fins de test. Voici un exemple de cela:
mock = Mockery :: mock ('Eloquent', 'Post'); fonction publique tearDown () Mockery :: close (); fonction publique testIndex () $ this-> mock -> shouldReceive ('all') -> once () -> andReturn ('foo'); $ this-> app-> instance ('Post', $ this-> mock); $ this-> call ('GET', 'posts'); $ this-> assertViewHas ('posts');Le principal avantage de cette restructuration est que, maintenant, la base de données ne sera jamais inutilement touchée. Au lieu de cela, en utilisant Mockery, nous vérifions simplement que le
tout
la méthode est déclenchée sur le modèle.$ this-> mock -> shouldReceive ('all') -> once ();Malheureusement, si vous choisissez de ne pas coder vers une interface et que vous injectez à la place
Poster
dans le contrôleur, un peu de ruse doit être utilisé afin de contourner l'utilisation de la statique par Eloquent, qui peut entrer en conflit avec Mockery. C’est pourquoi nous détournons à la fois lePoster
etÉloquent
classes dans le constructeur du test, avant le chargement des versions officielles. De cette façon, nous avons une table rase pour déclarer toute attente. L’inconvénient, bien sûr, est que nous ne pouvons utiliser aucune méthode existante, par le biais de méthodes Mockery, telles quemakePartial ()
.Le conteneur IoC
Le conteneur IoC de Laravel facilite considérablement l’injection de dépendances dans vos classes. Chaque fois qu'un contrôleur est demandé, il est résolu en dehors du conteneur IoC. En tant que tel, lorsque nous devons déclarer qu’une version simulée de
Poster
devrait être utilisé pour les tests, il suffit de fournir à Laravel l’instance dePoster
cela devrait être utilisé.$ this-> app-> instance ('Post', $ this-> mock);Pensez à ce code en disant: "Hé Laravel, quand vous avez besoin d’une instance de
Poster
, Je veux que tu utilises ma version moquée."Parce que l'application étend laRécipient
, nous avons accès à toutes les méthodes IoC directement.Lors de l’instanciation du contrôleur, Laravel exploite la puissance de la réflexion PHP pour lire le typehint et injecter la dépendance à votre place. C'est vrai; vous n'avez pas besoin d'écrire une seule liaison pour permettre cela; c'est automatisé!
Redirections
Une autre attente courante en matière d’écriture est de garantir que l’utilisateur soit redirigé vers le bon emplacement, par exemple lors de l’ajout d’une nouvelle publication à la base de données. Comment pourrions-nous accomplir cela?
# app / tests / controllers / PostsControllerTest.php fonction publique testStore () $ this-> mock -> shouldReceive ('create') -> once (); $ this-> app-> instance ('Post', $ this-> mock); $ this-> call ('POST', 'posts'); $ this-> assertRedirectedToRoute ('posts.index');En supposant que nous suivions une saveur reposante, pour ajouter un nouveau post, nous aurions
POSTER
à la collection, oudes postes
(ne confondez pas lePOSTER
méthode de requête avec le nom de la ressource, qui a juste le même nom).$ this-> call ('POST', 'posts');Ensuite, nous devons seulement tirer parti d'une autre des affirmations de l'aide de Laravel,
assertRedirectedToRoute
.Pointe: Lorsqu'une ressource est enregistrée auprès de Laravel (
Route :: ressource ()
), le framework enregistre automatiquement les routes nommées nécessaires. CourirRoutes d'artisan php
si jamais vous oubliez ce que sont ces noms.Vous préférerez peut-être aussi vous assurer que le
$ _POST
superglobal est passé à lacréer
méthode. Même si nous ne soumettons pas physiquement un formulaire, nous pouvons toujours le permettre, via leInput :: replace ()
méthode, ce qui nous permet de "stub" ce tableau. Voici le test modifié, qui utilise Mockeryavec()
méthode pour vérifier les arguments passés à la méthode référencée pardevrait recevoir
.# app / tests / controllers / PostsControllerTest.php fonction publique testStore () Input :: replace ($ input = ['title' => 'Mon titre']); $ this-> mock -> shouldReceive ('create') -> once () -> avec ($ input); $ this-> app-> instance ('Post', $ this-> mock); $ this-> call ('POST', 'posts'); $ this-> assertRedirectedToRoute ('posts.index');
Les chemins
Une chose que nous n'avons pas considérée dans ce test est la validation. Il devrait y avoir deux chemins séparés à travers le
le magasin
méthode, selon que la validation réussit ou non:
- Redirection vers le formulaire "Créer une publication" et affichage des erreurs de validation du formulaire..
- Rediriger vers la collection ou la route nommée,
posts.index
.Il est recommandé que chaque test ne représente qu'un seul chemin dans votre code..
Ce premier chemin sera pour la validation a échoué.
# app / tests / controllers / PostsControllerTest.php fonction publique testStoreFails () // Place l'étape pour une validation ayant échoué Input :: replace (['title' => "]); $ this-> app-> instance ('Post ', $ this-> mock); $ this-> call (' POST ',' posts '); // La validation a échoué devrait recharger le formulaire de création $ this-> assertRedirectedToRoute (' posts.create '); // Les erreurs doit être envoyé à la vue $ this-> assertSessionHasErrors (['title']);L'extrait de code ci-dessus déclare explicitement quelles erreurs devraient exister. Sinon, vous pouvez omettre l'argument de
assertSessionHasErrors
, dans ce cas, il se contentera de vérifier qu’un message a été flashé (votre traduction inclut la redirection).withErrors ($ errors)
).Maintenant pour le test qui gère la validation réussie.
# app / tests / controllers / PostsControllerTest.php fonction publique testStoreSuccess () // Définit l'étape de la validation réussie Input :: replace (['title' => 'Titre de Foo']]); $ this-> mock -> shouldReceive ('create') -> once (); $ this-> app-> instance ('Post', $ this-> mock); $ this-> call ('POST', 'posts'); // Devrait rediriger vers la collection, avec un message flash de succès $ this-> assertRedirectedToRoute ('posts.index', ['flash']);Le code de production de ces deux tests pourrait ressembler à ceci:
# app / controllers / PostsController.php fonction publique store () $ input = Input :: all (); // Nous allons exécuter la validation dans le contrôleur par souci de commodité // Vous devez l'exporter dans le modèle ou un service $ v = Validator :: make ($ input, ['title' => 'required']); if ($ v-> échoue ()) retour Redirect :: route ('posts.create') -> withInput () -> withErrors ($ v-> messages ()); $ this-> post-> create ($ input); return Redirect :: route ('posts.index') -> avec ('flash', 'Votre message a été créé!');Remarquez comment
Validateur
est imbriqué directement dans le contrôleur? En général, je vous recommande de résumer ceci à un service. De cette façon, vous pouvez tester votre validation indépendamment des contrôleurs ou des routes. Néanmoins, laissons les choses en l'état pour des raisons de simplicité. Une chose à garder à l’esprit est que nous ne nous moquons pas de laValidateur
, bien que vous puissiez certainement le faire. Comme cette classe est une façade, elle peut facilement être remplacée par une version simulée, via le logiciel Facade.devrait recevoir
méthode, sans que nous ayons à nous soucier d’injecter une instance par le constructeur. Gagner!# app / controllers / PostsController.php Validator :: shouldReceive ('make') -> once () -> andReturn (Mockery :: mock (['fail' => 'true']));De temps en temps, vous constaterez qu'une méthode à simuler doit renvoyer un objet, lui-même. Heureusement, avec Mockery, c'est un jeu d'enfant: il suffit de créer un simulacre anonyme et de passer un tableau, qui indique respectivement le nom de la méthode et la valeur de la réponse. En tant que tel:
Mockery :: mock (['fail' => 'true'])préparera un objet contenant un
échoue()
méthode qui retournevrai
.
Dépôts
Pour permettre une flexibilité optimale, plutôt que de créer un lien direct entre votre contrôleur et un ORM, comme Eloquent, il est préférable de coder vers une interface. L’avantage considérable de cette approche est que, si vous deviez peut-être échanger Eloquent contre, par exemple, Mongo ou Redis, cela nécessite littéralement de modifier une seule ligne. Encore mieux, le contrôleur n'a jamais besoin d'être touché.
Les référentiels représentent la couche d'accès aux données de votre application.
Qu'est-ce qu'une interface de gestion de la couche base de données d'un
Poster
ressembler? Cela devrait vous aider à démarrer.Cela peut certainement être étendu, mais nous avons ajouté les méthodes minimales pour la démo:
tout
,trouver
, etcréer
. Notez que les interfaces de référentiel sont stockées dansapp / référentiels
. Comme ce dossier n’est pas chargé automatiquement par défaut, nous devons mettre à jour lecomposer.json
fichier pour l'application pour le référencer.// composer.json "autoload": "classmap": [//… "app / repositories"]Quand une nouvelle classe est ajoutée à ce répertoire, n'oubliez pas de
composer dump-autoload -o
. le-o
, (optimiser) Le drapeau est facultatif, mais devrait toujours être utilisé, comme meilleure pratique.Si vous essayez d’injecter cette interface dans votre contrôleur, Laravel vous capturera. Aller de l'avant; essayez et voyez. Voici le modifié
PostController
, qui a été mis à jour pour injecter une interface, plutôt que lePoster
Modèle éloquent.post = $ post; fonction publique index () $ posts = $ this-> post-> all (); return View :: make ('posts.index', ['posts' => $ posts]);Si vous exécutez le serveur et affichez le résultat, vous rencontrerez la page d'erreur redoutée (mais magnifique) de Whoops, déclarant que "PostRepositoryInterface n'est pas instanciable."
Si vous y réfléchissez, bien sûr, le cadre est sifflant! Laravel est intelligent, mais ce n'est pas un lecteur d'esprit. Il faut savoir quelle implémentation de l'interface doit être utilisée dans le contrôleur.
Pour l'instant, ajoutons cette liaison à
app / routes.php
. Plus tard, nous ferons appel à des fournisseurs de services pour stocker ce type de logique..# app / routes.php App :: bind ('Repositories \ PostRepositoryInterface', 'Repositories \ EloquentPostRepository');Verbalise cet appel de fonction en tant que "Laravel, bébé, quand tu as besoin d'une instance de
PostRepositoryInterface
, Je veux que vous utilisiezEloquentPostRepository
."
app / repositories / EloquentPostRepository
sera tout simplement une enveloppe autour de Eloquent qui met en œuvrePostRepositoryInterface
. De cette façon, nous ne limitons pas l'API (et toute autre implémentation) à l'interprétation d'Eloquent; nous pouvons nommer les méthodes comme nous le souhaitons.Certains pourraient soutenir que le
Poster
modèle doit être injecté dans cette implémentation à des fins de testabilité. Si vous êtes d’accord, il suffit de l’injecter via le constructeur, comme d’habitude..C'est tout ce que ça devrait prendre! Actualisez le navigateur et tout devrait revenir à la normale. Seulement, maintenant, votre application est beaucoup mieux structurée et le contrôleur n’est plus lié à Eloquent..
Imaginons que, dans quelques mois, votre patron vous informe que vous devez échanger Eloquent avec Redis. Eh bien, puisque vous avez structuré votre application de manière à ce que vous puissiez le gérer à l'avenir, il vous suffit de créer le nouveau
app / repositories / RedisPostRepository
la mise en oeuvre:Et mettez à jour la reliure:
# app / routes.php App :: bind ('Repositories \ PostRepositoryInterface', 'Repositories \ RedisPostRepository');Instantanément, vous exploitez maintenant Redis dans votre contrôleur. Remarquez comment
app / controllers / PostsController.php
n'a jamais été touché? C'est la beauté!
Structure
Jusqu'ici dans cette leçon, notre organisation a fait un peu défaut. Liaisons IoC dans le
routes.php
fichier? Tous les référentiels regroupés dans un seul répertoire? Bien sûr, cela peut fonctionner au début, mais très vite, il deviendra évident que cela ne va pas à l'échelle.Dans la dernière section de cet article, nous allons PSR-ify notre code et utiliserons les fournisseurs de services pour enregistrer toutes les liaisons applicables..
PSR-0 définit les exigences obligatoires à respecter pour l'interopérabilité du chargeur automatique..
Un chargeur PSR-0 peut être enregistré auprès de Composer via le
psr-0
objet.// composer.json "autoload": "psr-0": "Way": "app / lib /"La syntaxe peut être déroutante au début. C'était certainement pour moi. Un moyen facile de déchiffrer
"Way": "app / lib /"
est de penser à vous-même, "Le dossier de base pour leFaçon
l'espace de noms est situé dansapp / lib
."Bien sûr, remplacez mon nom de famille par le nom de votre projet. La structure de répertoires correspondant à celle-ci serait:
Ensuite, plutôt que de regrouper tous les référentiels dans un les dépôts
répertoire, une approche plus élégante pourrait consister à les classer dans plusieurs répertoires, comme suit:
Il est essentiel que nous respections cette convention de dénomination et de dossier si nous voulons que le chargement automatique fonctionne comme prévu. Il ne reste plus qu'à mettre à jour les espaces de noms pour PostRepositoryInterface
et EloquentPostRepository
.
Et pour la mise en œuvre:
Nous y allons c'est beaucoup plus propre. Mais qu'en est-il de ces liaisons gênantes? Le fichier de routes peut être un endroit pratique pour expérimenter, mais cela n'a pas de sens de les stocker là en permanence. Au lieu de cela, nous allons utiliser des fournisseurs de services.
Les fournisseurs de services ne sont rien de plus que des classes d'amorçage pouvant être utilisées pour tout ce que vous souhaitez: enregistrer une liaison, accrocher un événement, importer un fichier de routes, etc..
Un fournisseur de services
registre()
sera déclenché automatiquement par Laravel.app-> bind ('Way \ Storage \ Post \ PostRepositoryInterface', 'Way \ Storage \ Post \ EloquentPostRepository');Pour faire connaître ce fichier à Laravel, il vous suffit de l’inclure dans
app / config / app.php
, dans lefournisseurs
tableau.# app / config / app.php 'providers' => array ('Illuminate \ Foundation \ Providers \ ArtisanServiceProvider', 'Illuminate \ Auth \ AuthServiceProvider', //… 'Way \ Storage \ StorageServiceProvider')Bien; nous avons maintenant un fichier dédié pour l'enregistrement de nouvelles liaisons.
Mise à jour des tests
Avec notre nouvelle structure en place, plutôt que de se moquer du modèle Eloquent, nous pouvons nous moquer
PostRepositoryInterface
. Voici un exemple d'un tel test:# app / tests / controllers / PostsControllerTest.php fonction publique testIndex () $ mock = Mockery :: mock ('Way \ Storage \ Post \ PostRepositoryInterface'); $ mock-> shouldReceive ('all') -> once (); $ this-> app-> instance ('Way \ Storage \ Post \ PostRepositoryInterface', $ mock); $ this-> call ('GET', 'posts'); $ this-> assertViewHas ('posts');Cependant, nous pouvons améliorer cela. Il va de soi que chaque méthode au sein de
MessagesControllerTest
nécessitera une version simulée du référentiel. En tant que tel, il est préférable d'extraire une partie de ce travail préparatoire dans sa propre méthode, comme ceci:# app / tests / controllers / PostsControllerTest.php fonction publique setUp () parent :: setUp (); $ this-> mock ('Way \ Storage \ Post \ PostRepositoryInterface'); fonction publique mock ($ class) $ mock = Mockery :: mock ($ class); $ this-> app-> instance ($ class, $ mock); retourne $ mock; fonction publique testIndex () $ this-> mock-> shouldReceive ('all') -> once (); $ this-> call ('GET', 'posts'); $ this-> assertViewHas ('posts');Pas mal, oui?
Maintenant, si vous voulez être super-mouche et que vous souhaitez ajouter une touche de logique de test à votre code de productio