IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Symfony PHP Discussion :

Symfony / PHPunit - Tester un service qui utilise TokenStorage en constructeur


Sujet :

Symfony PHP

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Homme Profil pro
    Développeur Web
    Inscrit en
    Octobre 2019
    Messages
    67
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Octobre 2019
    Messages : 67
    Par défaut Symfony / PHPunit - Tester un service qui utilise TokenStorage en constructeur
    Bonjour à tous,

    Je sollicite votre aide car j'essaie d'écrire des tests unitaires pour un de mes services sous Symfony 4, et pour l'instant je suis dans les choux.

    Ma classe AlerteService utilise différentes dépendances dans son constructeur, dont TokenStorageInterface qui me permet de récupérer l'id de l'utilisateur connecté.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
     
    //AlerteService
     
    class AlerteService
    {
        private $router;
     
        private $entityManager;
     
        private $clientAdresseRepository;
     
        private $clientContactRepository;
     
        private $clientRepository;
     
        private $user_id;
     
        public function __construct
        (
            RouterInterface $router,
            EntityManagerInterface $entityManager,
            TokenStorageInterface $tokenStorage
        )
        {
            $this->router = $router;
            $this->entityManager = $entityManager;
            $this->user_id = $tokenStorage->getToken()->getUser()->getId();
            $this->clientAdresseRepository = $entityManager->getRepository(ClientAdresse::class);
            $this->clientContactRepository = $entityManager->getRepository(ClientContact::class);
            $this->clientRepository = $entityManager->getRepository(Client::class);
        }
     
        public function alert(string $titre, string $message)
        {
            $alerte = new Alerte();
            $alerte->setTitre($titre);
            $alerte->setMessage($message);
            $alerte->setUserId($this->user_id);
     
            $this->entityManager->persist($alerte);
            $this->entityManager->flush();
     
            return true;
        }
    Et voici le test que je tente d'effectuer en vain :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    class AlerteServiceTest extends TestCase
    {
        public function testalert()
        {
            $arg1Mock = $this->createMock(RouterInterface::class);
            $arg2Mock = $this->createMock(EntityManagerInterface::class);
            $arg3Mock = $this->createMock(TokenStorage::class);
     
            $alerteService = new AlerteService($arg1Mock, $arg2Mock, $arg3Mock);
     
            $result = $alerteService->alert('salut', 'message');
     
            $this->assertEquals(true, $result);
        }
    }
    Qui me renvoie le message d'erreur suivant :
    App\Tests\Utils\AlerteServiceTest::testalert
    Error: Call to a member function getUser() on null
    Le problème reste le même si à la place j'écris :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $arg3Mock = $this->createMock(TokenStorageInterface::class);
    Du coup je me demande si c'est mon test qui est incorrect, ou si c'est mon service et son constructeur qui pose problème
    La moindre piste serait la bienvenue ...

    Merci d'avance

  2. #2
    Membre Expert
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2012
    Messages
    631
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2012
    Messages : 631
    Par défaut
    bonjour,
    dans ton service, il faut juste passer l'objet User à place de TokenStorageInterface.
    Quand tu vas faire appelle à ton service AlerteService dans un contrôleur c'est à ce moment que tu pourras passer le user connecté.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
     
     
    //AlerteService
     
    class AlerteService
    {
        private $router;
     
        private $entityManager;
     
        private $clientAdresseRepository;
     
        private $clientContactRepository;
     
        private $clientRepository;
     
        private $user;
     
        public function __construct
        (
            RouterInterface $router,
            EntityManagerInterface $entityManager,
            User $user
        )
        {
            $this->router = $router;
            $this->entityManager = $entityManager;
            $this->user = $user;
            $this->clientAdresseRepository = $entityManager->getRepository(ClientAdresse::class);
            $this->clientContactRepository = $entityManager->getRepository(ClientContact::class);
            $this->clientRepository = $entityManager->getRepository(Client::class);
        }
     
        public function alert(string $titre, string $message)
        {
            $alerte = new Alerte();
            $alerte->setTitre($titre);
            $alerte->setMessage($message);
            $alerte->setUserId($this->user->getId());
     
            $this->entityManager->persist($alerte);
            $this->entityManager->flush();
     
            return true;
        }
    au niveau de la classe de test tu peux soit mocker un objet User soit mocker un repository pour trouver un user donné:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    //class AlerteServiceTest 
     
      public function testalert()
      {
          $arg1Mock = $this->createMock(RouterInterface::class);
          $arg2Mock = $this->createMock(EntityManagerInterface::class);
          $user = $this->getUser();
          $alerteService = new AlerteService($arg1Mock, $arg2Mock, $user);
     
          $result = $alerteService->alert('salut', 'message');
          $this->assertEquals(true, $result);
    }
     
     /**
      * @return User
      */
      protected function getUser() :User
      {
          return $this->getMockBuilder(User::class)->getMock();
      }

  3. #3
    Membre éclairé
    Homme Profil pro
    Développeur Web
    Inscrit en
    Octobre 2019
    Messages
    67
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Octobre 2019
    Messages : 67
    Par défaut
    Bonjour,

    J'ai essayé rapidement mais je rencontre quelques soucis.
    Je me repenche dessus tout à l'heure et je ferai un retour plus complet

    En prenant en compte ta réponse, ça veut dire que ma méthode de placer directement TokenStorage (et d'autres dépendances) directement dans mon constructeur ne serait pas une bonne pratique ?
    Pas moyen de faire des tests si je procède comme ça ?

    Car l'avantage pour moi, c'était que mon AlerteService est autonome, avec l'injection de dépendance il récupérait tout seul TokenStorage, EntityManager, RouterInterface.
    Du coup il récupérait aussi l'utilisateur actif, sans avoir besoin de lui passer quoi que ce soit depuis le controller (j'essaye d'alléger au maximum mes controleurs).

    En tout cas merci pour ta réponse

  4. #4
    Membre Expert
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2012
    Messages
    631
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2012
    Messages : 631
    Par défaut
    Dans une architecture MVC il appartient au contrôleur de gérer une session, de récupérer le statut d'un utilisateur et de faire appelle à ta couche modèle. La partie business n'a pas à faire de distinguo utilisateur connecté ou pas d'autant plus qu'une application Web peut ne pas manipuler de session c'est le cas des applications exposant les ressources via l'API REST.
    Tu mets dans le constructeur que les dépendances dont ont besoin les méthodes de la classe service.

  5. #5
    Membre éclairé
    Homme Profil pro
    Développeur Web
    Inscrit en
    Octobre 2019
    Messages
    67
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Octobre 2019
    Messages : 67
    Par défaut
    Merci pour cette petite piqûre de rappel, ça ne fait pas de mal

    Je vais revoir un peu mon code et re-tenter mes tests.

Discussions similaires

  1. Test d'un service qui utilise un autre projet
    Par kevin254kl dans le forum Symfony
    Réponses: 1
    Dernier message: 07/01/2020, 11h09
  2. Retrouver le processus/service qui utilise un port
    Par CliffeCSTL dans le forum Windows
    Réponses: 4
    Dernier message: 05/03/2015, 16h35
  3. Classe Junit pour tester un Restful qui utilise @FormParam
    Par tunizar dans le forum Services Web
    Réponses: 1
    Dernier message: 04/06/2013, 16h24
  4. Réponses: 0
    Dernier message: 26/07/2011, 13h04
  5. Un service qui utilise le CPU à 100%
    Par t-student dans le forum Windows XP
    Réponses: 5
    Dernier message: 04/02/2008, 11h56

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo