Partage
  • Partager sur Facebook
  • Partager sur Twitter

Symfony 5-Conflit entre AbstractController et mock

Sujet résolu
    17 février 2020 à 9:33:26

    Bonjour à tous!

    J'ai un controller HomeController qui affiche ma page d'accueil et une liste de tricks (figures de snow).

    J'aimerais faire des tests unitaires dessus pour vérifier qu'il revoit bien un objet Reponse. Voici donc le code que j'ai fait:

    <?php
    
    namespace App\Controller;
    
    use App\Repository\TrickRepository;
    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
    use Symfony\Component\Routing\Annotation\Route;
    
    class HomeController extends AbstractController
    {
        /**
         * @Route("/", name="home")
         */
        public function index(TrickRepository $repo)
        {
            $tricks = $repo->findAll();
    
            return $this->render('home.html.twig', [
                'tricks' => $tricks,
            ]);
        }
    }
    <?php
    
    namespace App\Tests\Controller;
    
    use App\Controller\HomeController;
    use App\Repository\TrickRepository;
    use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
    use Symfony\Component\HttpFoundation\Response;
    
    class HomeControllerTest extends WebTestCase
    {
        public function testIndex()
        {
            $repo = $this->createMock(TrickRepository::class);
            $homepage = new HomeController();
    
            $returnTest = $homepage->index($repo);
            $this->assertInstanceOf(Response::class, $returnTest);
    
        }
    }
    

    Si je lance PhpUnit j'ai cette erreur :

    There was 1 error:
    
    1) App\Tests\Controller\HomeControllerTest::testIndex
    Error: Call to a member function has() on null
    
    C:\Users\Shiyo\Desktop\Formation\Projet\Projet6_SnowTricks\Code\SnowTricks\vendor\symfony\framework-bundle\Controller\AbstractController.php:245
    C:\Users\Shiyo\Desktop\Formation\Projet\Projet6_SnowTricks\Code\SnowTricks\vendor\symfony\framework-bundle\Controller\AbstractController.php:257
    C:\Users\Shiyo\Desktop\Formation\Projet\Projet6_SnowTricks\Code\SnowTricks\src\Controller\HomeController.php:19
    C:\Users\Shiyo\Desktop\Formation\Projet\Projet6_SnowTricks\Code\SnowTricks\tests\Controller\HomeControllerTest.php:18
    


    C'est le AbstractController avec sa fonction has() qui merde car il détecte que la liste des tricks est vide (forcément c'est un mock). Le seul moyen que j'ai trouvé pour enlever cette erreur est de supprimer le

    extends AbstractController

    en modifiant toute la classe en conséquence pour qu'elle fonctionne quand même correctement. Je trouve nul de modifier tous mes controllers en les rendant moins lisibles juste pour des test unitaires. Il doit y avoir un autre moyen mais je n'arrive pas à trouver lequel.

    Des idées?


    • Partager sur Facebook
    • Partager sur Twitter
      17 février 2020 à 10:46:03

      Salut

      Pourquoi tu passe un new HomeController() ?

      • Partager sur Facebook
      • Partager sur Twitter
        17 février 2020 à 11:07:23

        Salut hous,

        Il faut que je crée la classe pour lancer sa fonction index() et tester ce qu'elle retourne, non?

        • Partager sur Facebook
        • Partager sur Twitter
          18 février 2020 à 2:38:48

          Tu as cette erreur parce que ton AbstractControler fait un 
          $this->container->has

          Et comme t'as directement créer un HomeController tu dois lui donner un ContainerInterface:

          $homepgae->setContainer($container); // un object Container que tu dois récupérer...


          Mais pourquoi ne pas faire comme dans la doc :

          // tests/Controller/PostControllerTest.php
          namespace App\Tests\Controller;
          
          use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
          
          class PostControllerTest extends WebTestCase
          {
              public function testShowPost()
              {
                  $client = static::createClient();
          
                  // Tu passe juste l'url à tester 
                  $client->request('GET', '/post/hello-world');
          
                  $this->assertEquals(200, $client->getResponse()->getStatusCode());
              }
          }
          
          • Partager sur Facebook
          • Partager sur Twitter

          Making functional apps for digital products @NEOTIC

          -

            18 février 2020 à 8:30:11

            Merci pour ta réponse rand0mdev (pas mal le pseudo d'ailleurs ^^).

            J'avais fait comme dans la doc mais mon mentor me dit que c'est des tests fonctionnels et non unitaires.. :euh:

            • Partager sur Facebook
            • Partager sur Twitter
              18 février 2020 à 17:39:51

              Oui c'est des tests fonctionnels et c'est ce que tu veux faire non? Car tu fais deja interagir pas mal de classes.

              D'ailleurs pour de simples tests unitaires tu peux faire hériter ta classe de PHPUnit\Framework\TestCase ca suffit.

              tu peux comparer les deux en regardant le code généré par le maker bundle:

              php bin/console make:unit-test
              php bin/console make:functional-test



              • Partager sur Facebook
              • Partager sur Twitter

              Making functional apps for digital products @NEOTIC

              -

                20 février 2020 à 10:49:18

                Merci je comprend un peu mieux la différence entre les deux.

                Il faut pour le projet que je face des tests unitaires uniquement. Je dois simplement vérifier que mon controller renvois un objet Response. Or je ne peut pas le faire à cause du Abstract Controller qui bloque avec sa fonction has().

                • Partager sur Facebook
                • Partager sur Twitter
                  20 février 2020 à 13:54:30

                  Normalement ça peut marcher en faisant cela:

                      public function testIndex()
                      {
                          static::bootKernel();
                  
                          $repo = $this->createMock(TrickRepository::class);
                          $homepage = new HomeController();
                  
                          $homepage->setContainer(static::$container);
                   
                          $returnTest = $homepage->index($repo);
                          $this->assertInstanceOf(Response::class, $returnTest);
                   
                      }


                  Mais est-ce que ça reste des tests unitaires ? je ne pense pas.

                  Bien sur ta classe doit hériter de WebTestCase 

                  • Partager sur Facebook
                  • Partager sur Twitter

                  Making functional apps for digital products @NEOTIC

                  -

                    20 février 2020 à 14:24:24

                    En effet comme ça ça fonctionne ! Merci beaucoup!

                    Je vais me pencher sur la différence entre test unitaire et fonctionnel car visiblement j'ai pas encore tout saisit. Merci pour les infos et le code!

                    • Partager sur Facebook
                    • Partager sur Twitter

                    Symfony 5-Conflit entre AbstractController et mock

                    × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                    × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                    • Editeur
                    • Markdown