Bonjour à tous,

je découvre les test unitaires et j'aurais quelques questions à vous poser.
J'essaie d'écrire les tests des fonctions du plugin Media de Grafikart que je suis en train de refaire pour CakePHP3 et je suis confronté à un petit problème de compréhension.

Lorsque je fait un test qui passe et que je regarde le code coverage, celui ci reste toujours rouge alors qu'il me semble que le test couvre bien la fonction ou au moins une partie... J'avoue qu'à ce stade, je ne comprends pas trop pourquoi ça reste comme ça.
C'est un peu comme si mon test n'était pas bon (j'ai juste ?)

Voici la simple fonction de mon Entity que j'essaie de tester :

public function getIconAndType()
{
        if(isset($this->file)){
            $pathinfo = \pathinfo($this->file);
            $extension = $pathinfo['extension'];
            if(!\in_array($extension, $this->pictures)){
                $this->type = $extension;
                $this->icon = 'Media.' . $extension . '.png';
            }else{
                $this->type = 'pic';
                $this->icon = $this->file;
            }
        }
        return $this;
 }

et son test unitaire (seul un partie est faite) :

public function testGetIconAndTypeWithPicType()
{
        if(isset($this->file)){
          $pathinfo = \pathinfo($this->file);
            $extension = $pathinfo['extension'];
          if(in_array($extension, $this->pictures)){
            $this->type = 'pic';
            $this->icon = WWW_ROOT . DS . 'img' . DS . 'upload' . DS . '2015' . DS . '07' . DS . 'testHelper.png';
            $this->assertEquals('pic', $this->type);
          }         
        }
}

Je pense que mon test est mal rédigé mais je n'arrive pas à voir comment faire pour l'améliorer et l'optimiser.
Je tiens à préciser que je ne demande pas qu'on m'écrive le test de la fonction mais plutôt qu'on m'aiguille sur les erreurs que j'ai pu faire en la rédigeant afin de ne pas les reproduire pour la suite des tests.

Merci d'avance pour vos éclairages,
Romain

7 réponses


Tu n'utilises jamais la fonction getIconAndType() dans ton test.
En fait le test peut s'effectuer même si tu supprimes la fonction de ton code de ce que je comprends donc effectivement le code coverage n'est pas impacté.

De plus ton assertion est dans un if, il y a donc des chances que parfois aucune assertion ne soit faite, phpunit n'aime pas beaucoup ça générallement.

Romano83
Auteur

Salut antograssiot,
désolé pour cette réponse tardive.
Effectivement, je m'en suis aperçu après avoir fais d'autres tests... Je n'ai pas eu le temps de retester cette fonction cette semaine mais dès que j'ai un peu de temps libre, je posterais le résultat sur ce sujet.
Par ailleurs, je pense que je vais laisser ce topic ouvert car je vais surement avoir d'autres questions liées aux tests unitaires !

Romano83
Auteur

Au final, je me retrouve une fois de plus avec quelques petits problèmes au niveau des tests unitaires...

J'essaie tant bien que mal de tester mon controller mais chaque fonction dudit controller est dépendante d'une fonction se situant dans l'AppController. Le problème, c'est que je n'arrive pas à passer cette restriction en utilisant les tests unitaires...

Je précise tout de même qu'il s'agit de controller situé dans un plugin et que l'AppController est celui de l'application, pas celui du plugin (c'est juste histoire de corsé un peu plus la chose !)

Voici le Controller :

public function canUploadMedias($ref, $refId)
    {
        if (method_exists('App\Controller\AppController', 'canUploadMedias')) {
            return parent::canUploadMedias($ref, $refId); // impossible de passer dans cette condition avec les tests. Voir plus bas !
        } else {
            return false;
        }
    }
public function index($ref, $refId)
    {
        if (! $this->canUploadMedias($ref, $refId)) {
            throw new ForbiddenException();
        }
        $this->loadModel($ref);
        $this->set(compact('ref', 'refId'));
        if (! in_array('Media', $this->$ref->Behaviors()->loaded())) {
            return $this->render('nobehavior');
        }
        $id = isset($this->request->query['id']) ? $this->request->query['id'] : false;
        $medias = $this->Medias->find('all', [
            'conditions' => [
                'ref_id' => $refId,
                'ref' => $ref
            ]
        ])->toArray();
        $medias = ! empty($medias) ? $medias : null;
        $thumbID = false;
        if ($this->$ref->hasField('media_id')) {
            $entity = $this->$ref->get($refId);
            $thumbID = $entity->media_id;
        }
        $extensions = $this->$ref->medias['extensions'];
        $editor = isset($this->request->query['editor']) ? $this->request->query['editor'] : false;
        $this->set(compact('id', 'medias', 'thumbID', 'editor', 'extensions'));
    }

et ma class de test :

public function testIndexWithoutCanUploadMediasMethod()
    {
        $this->get('/media/medias/index/Posts/1');

        $this->assertResponseError();
    }

    public function testIndexWithoutBehaviorLoaded()
    {   
        // Pour cette partie, il me semble que c'est presque bon... A confirmer !
        $this->Posts = $this->getMockBuilder('\App\Controller\AppController') 
                    ->setMethods(['canUploadMedias'])
                    ->getMock();
        $this->Posts->expects($this->once())
                    ->method('canUploadMedias')
                    ->willReturn(true);

            $this->get('/media/medias/index/Posts/1');

            $this->assertResponseOk();
            $this->assertResponseContains('<h1>Erreur</h1>');
            $this->assertResponseContains('<p>"`La Table \'{0}Table\' n\'a pas le comportement \'Media\'"</p>');
    }

Autant mon premier test réussit sans problème, autant pour le deuxième, je suis n'arrive pas à rentrer dans la condition "method_exist" de la fonction canUploadMedias...

Une idée pour que j'arrive à faire "accepter" à mon test que cette fonction retourne bien true...

Merci d'avance !

Romano83
Auteur

Toujours pas d'idée ?
Je galère pas mal pour essayé de résoudre ce problème...

Désolé je n'ai pas pris le temps de regarder ton problème mais tu devrais faire un debug de parent::canUploadMedias pour vérifier que la classe est bien celle que tu attends car cela ne paraît pas évident.

Romano83
Auteur

Salut, pas de problème !
J'avais déjà fais un debug de parent::canUploadMedias et je n'obtenais pas la bonne classe.
Depuis que j'ai posté ce problème, j'ai trouvé une solution qui n'est peut être pas la mieux mais qui à le mérite de fonctionner. J'ai tout simplement rajouté un dossier "App" dans mes dossiers de tests. Grâce aux namespaces, je peux récupérer les classes qui sont à l'intérieurs sans avoir de conflits !

Par contre, je me retrouve avec une nouvelle erreur que je ne comprends pas. J'ai "mocké" une fonction du model comme ceci :

$this->Medias = $this->getMockForModel('Media.Medias', array('move_uploaded_file'));
$this->Medias->expects($this->any())->method('move_uploaded_file')->will($this->returnCallback('test_move_uploaded_file'));

Le problème c'est que j'ai une fonction dans mon model qui l'appelle. Or, j'ai cette erreur qui apparait :

call_user_func_array() expects parameter 1 to be a valid callback, function 'test_move_uploaded_file' not found or invalid function name

Une idée ?

Il n'a pas l'air de trouver ta fonction de callback. Sur ton repo Github, je ne trouve aucune fonction avec ce nom.