2017-08-10 1 views
1

J'essaie de créer un test unitaire pour mon application mais j'aimerais avoir quelques conseils.Comparer des entités en fonction de leur ID pendant le test unitaire

J'ai ces méthodes:

/** 
* This methods check if the user can apply to the team, it search if he have a username for the game and if he doesn't already applied for another team in the same tournament 
* @param User $user 
* @param Team $team 
* @return bool|string 
*/ 
public function canApply(User $user, Team $team) { 
    if ($user->getGamingUsername($team->getTournament()->getGame()) === null) { 
     return "Vous devez avoir un nom d'utilisateur pour pouvoir vous inscrire, renseignez le dans \"Mon profil\""; 
    } else if (false !== $teamAlreadyIn = $this->isAlreadyApplicant($user, $team)) { 
     return "Vous avez déjà postulé pour une équipe pour ce tournoi : 
     <a href=\"".$this->router->generate("mgd_team_show", array("id" => $teamAlreadyIn->getId()))."\">".htmlspecialchars($teamAlreadyIn->getName())."</a>"; 
    } 
    return true; 
} 

/** 
* This method search if the user is already in a team for the same tournament than the one passed in argument 
* @param User $user 
* @param Team $team 
* @return bool|Team|mixed 
*/ 
public function isAlreadyApplicant($user, Team $team) { 
    if (!$user || !$this->authorizationChecker->isGranted("ROLE_USER")) { 
     return false; 
    } 

    foreach ($user->getApplications() as $userTeam) { 
     /** @var Team $userTeam */ 
     if ($userTeam->getTournament()->getId() === $team->getTournament()->getId()) { 
      return $userTeam; 
     } 
    } 

    foreach ($user->getTeams() as $userTeam) { 
     /** @var Team $userTeam */ 
     if ($userTeam->getTournament()->getId() === $team->getTournament()->getId()) { 
      return $userTeam; 
     } 
    } 

    foreach ($user->getManagedTeam() as $userTeam) { 
     /** @var Team $userTeam */ 
     if ($userTeam->getTournament()->getId() === $team->getTournament()->getId()) { 
      return $userTeam; 
     } 
    } 
    return false; 
} 

Comme vous pouvez le voir, la première (canApply) appeler le second (isAlreadyApplicant).

Mais quand j'essaye de tester canApply, j'ai quelques problèmes: cet appel de méthode isAlreadyApplicant et dans celui-ci je compare en fonction de l'id les tournois.

Dans ma classe de test, je ne peux pas "-> setId()" parce que c'est une méthode privée. Alors, comment suis-je censé gérer cela? Vaut-il mieux récupérer un élément de ma base de données?

À l'heure actuelle, l'un de mes testMethod ressemble à ceci:

/** 
* The user is connected and try to apply to a team and applied for another team for another game 
*/ 
public function testCanApplySecondTeamAnotherGame() { 
    $user = new User(); 
    $game = new Game(); 
    $anotherGame = new Game(); 

    $team = new Team(); 
    $anotherTeam = new Team(); 

    $tournament = new TournamentTeam(); 
    $anotherTournament = new TournamentTeam(); 

    $team->setTournament($tournament); 
    $anotherTeam->setTournament($anotherTournament); 

    $tournament->setGame($game); 
    $anotherTournament->setGame($anotherGame); 

    $game->setName("TestGame"); 
    $anotherGame->setName("AnotherGame"); 

    $gamingProfile = new GamingProfile(); 
    $gamingProfile->setGame($game); 
    $gamingProfile->setUsername("TestGameUsername"); 

    $anotherGamingProfile = new GamingProfile(); 
    $anotherGamingProfile->setGame($anotherGame); 
    $anotherGamingProfile->setUsername("TestAnotherGameUsername"); 

    $user->setGamingProfiles(new ArrayCollection(array($gamingProfile, $anotherGamingProfile))); 

    $user->addApplication($anotherTeam); 
    $user->addTeam($anotherTeam); 

    $router = $this->createMock(Router::class); 
    $authorizationChecker = $this->createMock(AuthorizationCheckerInterface::class); 
    $authorizationChecker->method("isGranted")->willReturn(true); 

    $applicationChecker = new ApplicationChecker($router, $authorizationChecker); 
    //Here, we try to apply to a team 
    $this->assertTrue($applicationChecker->canApply($user, $team)); 

} 

Si vous avez des questions, ne hésitez pas! Passez une bonne journée!

+0

Il est généralement déconseillé, mais vous pouvez définir des propriétés privées avec la bibliothèque de simulation Phpunit. – svgrafov

+0

Ceci n'est pas un test unitaire, c'est un test d'intégration. – localheinz

+0

Désolé je pensais qu'un test d'intégration était un test unitaire – Alexandre

Répondre

1

Ce code est plus couplé et sera difficile à tester de manière simple.

Je vous conseille de prendre la méthode isAlreadyApplicant et passer dans un service par exemple. Après l'injection de dépendance, injectez le nouveau service dans votre service actuel (j'espère que c'est un service).

Dependency Injection Documentation

Alors maintenant, vous pouvez railler le nouveau service avec la méthode isAlreadyApplicant.

Ceci est pour le test unitaire.


Si vous avez besoin des tests fonctionnels, vous pouvez créer une classe, définissez l'ID et de l'utiliser au lieu de créer new Team() afin que vous puissiez contrôler votre classe parce que vous ne testez pas la classe d'entité, mais la fonction.


Une autre solution consiste à se moquer de la bibliothèque pour définir les propriétés privées dans vos tests, mais je n'aime pas cette solution

+0

Oui, c'est dans un même service mais ça ne changera pas le problème, quand je testerai isAlreadyApplicant, j'aurai le même problème.Si je dois créer pour chaque entité un autre entityTest, il faudra beaucoup de classe pour l'exécuter, je ne veux pas faire ceci:/ – Alexandre

+0

Ok mais votre code est trop couplé, quand vous devez tester isAlreadyApplicant vous devez se moquer de votre entité avec phpunit vous n'avez pas besoin de classe craete, je vous conseille de séparer It et mock service et entité @Alexandre –

+0

Quand vous dites que mon code est trop couplé, c'est seulement pour le test unitaire ou en général? Je vais séparer ces deux en deux service, merci pour le conseil. J'ai réussi à se moquer des entites et ça marche (mais je partagerai mon service) – Alexandre

0

Au lieu d'utiliser new User() dans le test, vous devez se moquer de ces objets. Ensuite, vous pouvez simuler n'importe quelle méthode, vous n'aurez donc pas besoin d'utiliser $user->setId() car vous pourrez obtenir $userMock->method('getId')->willReturn(10). Donc, au lieu d'instancier de nouveaux objets et de définir des valeurs avec des setters, moquez ces objets et talonnez les getters.

Voir https://phpunit.de/manual/current/en/test-doubles.html pour les références.

+0

Ouais, j'ai réussi à comprendre cela avec la réponse de @Alessandro. Merci de votre aide – Alexandre