Test des contrôleurs Laravel

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.

  • Isoler: Simulez toutes les dépendances (en excluant peut-être le Vue).
  • Appel: Déclencher la méthode de contrôleur souhaitée.
  • Assurer: Effectuer des assertions en vérifiant que la scène a été définie correctement.

Bonjour tout le monde des tests de contrôleurs

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'); 

La surcharge est ton ami

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 de PostsController 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. le assertViewHas 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 utile assertInstanceOf 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 de Illuminate \ 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 le Poster 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 que makePartial ().

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 de Poster 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 la Ré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, ou des postes (ne confondez pas le POSTER 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. Courir Routes 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é à la créer méthode. Même si nous ne soumettons pas physiquement un formulaire, nous pouvons toujours le permettre, via le Input :: replace () méthode, ce qui nous permet de "stub" ce tableau. Voici le test modifié, qui utilise Mockery avec() méthode pour vérifier les arguments passés à la méthode référencée par devrait 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:

  1. Redirection vers le formulaire "Créer une publication" et affichage des erreurs de validation du formulaire..
  2. 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 la Validateur, 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 retourne vrai.


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, et créer. Notez que les interfaces de référentiel sont stockées dans app / référentiels. Comme ce dossier n’est pas chargé automatiquement par défaut, nous devons mettre à jour le composer.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 le Poster 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 utilisiez EloquentPostRepository."

app / repositories / EloquentPostRepository sera tout simplement une enveloppe autour de Eloquent qui met en œuvre PostRepositoryInterface. 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 le Façon l'espace de noms est situé dans app / lib."Bien sûr, remplacez mon nom de famille par le nom de votre projet. La structure de répertoires correspondant à celle-ci serait:

  • app /
    • lib /
    • Façon/

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:

  • app /
    • lib /
    • Façon/
      • Espace de rangement/
      • Poster/
        • PostRepositoryInterface.php
        • EloquentPostRepository.php

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