Organisation des Tests de PHPUnit dans les espaces de noms
je vois deux options pour organiser les tests de L'unité PHPUnit en une hiérarchie d'espace de noms. Quels sont les avantages/inconvénients de ces deux approches? Existe-il des défauts évidents, je n'ai pas considéré que serait le meilleur choix évident?
Examiner un échantillon de classe comme SomeFrameworkUtilitiesAwesomeClass
:
approche 1: placer chaque classe de TestCase dans le même espace de noms que le couvert classe.
SomeFrameworkUtilitiesAwesomeClassTest
- les Avantages
- conforme à l'approche traditionnelle de rédaction des tests PHPUnit.
- désavantages
- Moins de flexibilité.
- semble briser le principe derrière l'utilisation des namespaces - des tests non liés sont groupés dans le même namespace.
- les Avantages
Approche 2: placez chaque TestCase dans un espace de noms nommé d'après la classe couverte.
SomeFrameworkUtilitiesAwesomeClassTest
- les Avantages
- fournit un moyen très facile / évident de grouper plusieurs classes de TestCase liées ensemble, disons pour différentes suites de test.
- désavantages
- pourrait donner lieu à une hiérarchie plus profonde et plus complexe.
- les Avantages
3 réponses
Ma solution proposée et le raisonnement derrière cela:
mise en page du dossier:
.
├── src
│ ├── bar
│ │ └── BarAwesomeClass.php
│ └── foo
│ └── FooAwesomeClass.php
└── tests
├── helpers
│ └── ProjectBaseTestClassWithHelperMethods.php
├── integration
│ ├── BarModuleTest.php
│ └── FooModuleTest.php
└── unit
├── bar
│ └── BarAwesomeClassTest.php
└── foo
└── FooAwesomeClassTest.php
helpers/
le dossier contient des classes qui ne sont pas des tests mais qui ne sont utilisées que dans un contexte de test. Habituellement ce dossier contient une classe BaseTestClass peut-être contenant des méthodes d'aide spécifiques au projet et un couple de classes stub faciles à réutiliser de sorte que vous n'avez pas besoin d'autant de moqueries.
unit/
les plans des dossiers 1:1 vers le src/
. Donc pour chaque classe de production il y a une classe qui contient tous les unité tests pour cette classe.
les espaces de noms
approche 1: Placez chaque classe de TestCase dans le même espace de noms que la classe couverte.
cette approche de dossier devrait résoudre un de vos inconvénients approche 1. Vous avez encore la flexibilité d'avoir plus de tests qu'une simple cartographie 1:1 pourrait vous donner mais tout est commandé et en place.
semble briser le principe derrière l'utilisation des namespaces - des tests non liés sont groupés dans le même namespace.
si les tests semblent "sans rapport", peut-être le code de production a-t-il le même problème?
C'est vrai que les tests ne dépendent pas l'un de l'autre mais ils peuvent utiliser leurs classes "proches" comme moqueries ou utiliser les vraies dans le cas de DTOs ou D'objets de valeur. Donc, je dirais qu'il y a une connexion.
approche 2: Placez chaque TestCase dans un espace de noms nommé d'après la classe couverte.
il y a quelques projets qui font cela mais habituellement ils le structurent un peu différemment:
Ce n'est pas \SomeFramework\Utilities\AwesomeClass\Test
, mais \SomeFramework\Tests\Utilities\AwesomeClassTest
et ils gardent toujours le mapping 1:1, mais avec le namespace de test supplémentaire ajouter.
namespace de test supplémentaire
mon avis personnel est que je n'aime pas avoir des namespaces de test séparés et je vais essayer de trouver un couple pour les arguments pour et contre ce choix:
les Tests devraient servir de documentation sur la façon d'utiliser une classe
lorsque la classe réelle est dans un autre espace de noms, les tests montrent comment utiliser cette classe en dehors de son propre module.
quand la classe réelle est dans le même espace de noms, les tests montrent comment l'utilisation de cette classe de l'intérieur de ce module.
les différences sont assez mineures (habituellement quelques énoncés d ' "utilisation" ou des chemins entièrement qualifiés)
quand on a la possibilité de dire $this->getMock(AwesomeClass::CLASS)
en PHP 5.5 au lieu de $this->getMock('\SomeFramework\Utilities\AwesomeClass')
chaque maquette nécessitera une déclaration d'utilisation.
pour moi l'utilisation dans le module est plus valable pour la plupart des classes
pollution de L'espace de nommage "Production"
quand vous dites new \SomeFramework\Utilities\A
l'achèvement automatique pourriez vous montrer AwesomeClass
et AwesomeClassTest
et certaines personnes ne veulent pas que. Pour un usage externe, ou lors de l'expédition de votre source qui n'est pas un problème bien sûr puisque les tests ne sont pas expédiés, mais il pourrait être quelque chose à considérer.
il y a une troisième option que j'utilise et qui s'adapte à niceley avec composer autoloading: insérez un Test
namespace après le premier pas dans la hiérarchie. Dans votre cas, ce namespace serait \SomeFramework\Tests\Utilities\
et la classe serait \SomeFramework\Tests\Utilities\AwesomeClassTest
.
vous pouvez alors soit mettre les tests ensemble avec les autres classes dans le \SomeFramework\Test
répertoire, ou les mettre dans un répertoire séparé. Vos informations autoload pour composer.json
pourrait ressembler à ceci:
{
"autoload": {
"psr-0": {
"SomeFramework\": "src/",
}
},
"autoload-dev": {
"psr-0": {
"SomeFramework\Tests\": "tests/"
}
}
}
avantages de la troisième approche sont les suivantes:
- séparation des essais et du code de production
- hiérarchies de dossiers similaires pour les tests et les classes de production
- Facile le chargement automatique
je préfère la première approche pour maintenir la cohérence--avec la pratique de PHPUnit et nos autres projets. De plus, Je ne crée qu'un seul cas de test par classe sous test. Mettre chacun dans son propre espace de noms semble exagéré. Comme L'a dit KingCrunch, les tests sont liés parce que les classes qu'ils testent sont liées.
de temps en temps un cas de test nécessite des fichiers de support tels que fixtures, mais ceux-ci sont facilement organisés en un sous-répertoire / namespace nommé pour la classe et sont souvent partagés entre plusieurs cas de test.
un gros inconvénient à la deuxième méthode est que le nom de chaque cas de test est Test
qui aura plusieurs ramifications:
- plusieurs fenêtres de test ouvertes auront toutes le même nom.
- la fonctionnalité "open type by name" de votre IDE (CTRL-O dans NetBeans) sera inutile pour les tests.
- votre clé IDE "go to test" (Ctrl-SHIFT-T dans NetBeans) pourrait également échouer.