Dois-je initialiser les champs de classe lors de la déclaration comme ceci?
public class SomeTest extends TestCase
{
private final List list = new ArrayList();
public void testPopulateList()
{
// Add stuff to the list
// Assert the list contains what I expect
}
}
Ou dans setUp () comme ça?
public class SomeTest extends TestCase
{
private List list;
@Override
protected void setUp() throws Exception
{
super.setUp();
this.list = new ArrayList();
}
public void testPopulateList()
{
// Add stuff to the list
// Assert the list contains what I expect
}
}
J'ai tendance à utiliser le premier formulaire car il est plus concis et me permet d'utiliser les champs finaux. Si je n'ai pas besoin d'utiliser la méthode setUp () pour la configuration, dois-je quand même l'utiliser et pourquoi?
Clarification:
JUnit instanciera la classe de test une fois par méthode de test. Cela signifie que list
sera créé une fois par test, quel que soit l'endroit où je le déclare. Cela signifie également qu'il n'y a pas de dépendances temporelles entre les tests. Il semble donc qu'il n'y ait aucun avantage à utiliser setUp (). Cependant, la FAQ JUnit a de nombreux exemples qui initialisent une collection vide dans setUp (), donc je pense qu'il doit y avoir une raison.
Réponses:
Si vous vous interrogez spécifiquement sur les exemples de la FAQ JUnit, tels que le modèle de test de base , je pense que la meilleure pratique présentée ici est que la classe testée doit être instanciée dans votre méthode setUp (ou dans une méthode de test) .
Lorsque les exemples JUnit créent un ArrayList dans la méthode setUp, ils testent tous le comportement de cet ArrayList, avec des cas tels que testIndexOutOfBoundException, testEmptyCollection, etc. La perspective de quelqu'un qui écrit un cours et s'assure que cela fonctionne correctement.
Vous devriez probablement faire la même chose lorsque vous testez vos propres classes: créez votre objet dans setUp ou dans une méthode de test, afin que vous puissiez obtenir un résultat raisonnable si vous le cassez plus tard.
D'un autre côté, si vous utilisez une classe de collection Java (ou une autre classe de bibliothèque, d'ailleurs) dans votre code de test, ce n'est probablement pas parce que vous voulez le tester - c'est juste une partie du montage de test. Dans ce cas, vous pouvez supposer que cela fonctionne comme prévu, donc l'initialiser dans la déclaration ne sera pas un problème.
Pour ce que ça vaut, je travaille sur une base de code assez volumineuse, vieille de plusieurs années, développée par TDD. Nous initialisons habituellement les choses dans leurs déclarations en code de test, et depuis un an et demi que je suis sur ce projet, cela n'a jamais posé de problème. Il y a donc au moins des preuves anecdotiques que c'est une chose raisonnable à faire.
la source
J'ai commencé à creuser moi-même et j'ai trouvé un avantage potentiel à utiliser
setUp()
. Si des exceptions sont levées pendant l'exécution desetUp()
, JUnit imprimera une trace de pile très utile. D'un autre côté, si une exception est levée pendant la construction de l'objet, le message d'erreur indique simplement que JUnit n'a pas pu instancier le scénario de test et vous ne voyez pas le numéro de ligne où l'échec s'est produit, probablement parce que JUnit utilise la réflexion pour instancier le test Des classes.Rien de tout cela ne s'applique à l'exemple de création d'une collection vide, car cela ne sera jamais lancé, mais c'est un avantage de la
setUp()
méthode.la source
En plus de la réponse d'Alex B.
Il est même nécessaire d'utiliser la méthode setUp pour instancier des ressources dans un certain état. Faire cela dans le constructeur n'est pas seulement une question de minutage, mais en raison de la façon dont JUnit exécute les tests, chaque état de test serait effacé après en avoir exécuté un.
JUnit crée d'abord des instances de testClass pour chaque méthode de test et commence à exécuter les tests après la création de chaque instance. Avant d'exécuter la méthode de test, sa méthode de configuration est exécutée, dans laquelle un état peut être préparé.
Si l'état de la base de données était créé dans le constructeur, toutes les instances instancieraient l'état de la base de données l'une après l'autre, avant d'exécuter chaque test. À partir du deuxième test, les tests s'exécuteraient avec un état incorrect.
Cycle de vie JUnits:
Avec quelques enregistrements dans un test avec deux méthodes de test, vous obtenez: (number est le hashcode)
la source
@BeforeClass
dans JUnit 4.Dans JUnit 4:
@Before
méthode pour détecter les échecs.final
, exactement comme indiqué dans la question,@Before
pour intercepter les échecs.@BeforeClass
, mais faites attention aux dépendances entre les tests.L'initialisation dans une
@Before
méthode ou une méthode de test vous permet d'obtenir un meilleur rapport d'erreur en cas d'échec. Ceci est particulièrement utile pour instancier la classe en cours de test (que vous pourriez casser), mais est également utile pour appeler des systèmes externes, comme l'accès au système de fichiers ("fichier non trouvé") ou la connexion à une base de données ("connexion refusée").Il est acceptable d'avoir un standard simple et de toujours l'utiliser
@Before
(erreurs claires mais verbeuses) ou toujours initialiser dans la déclaration (concis mais donne des erreurs déroutantes), car les règles de codage complexes sont difficiles à suivre, et ce n'est pas un gros problème.L'initialisation dans
setUp
est une relique de JUnit 3, où toutes les instances de test ont été initialisées avec empressement, ce qui pose des problèmes (vitesse, mémoire, épuisement des ressources) si vous effectuez une initialisation coûteuse. Ainsi, la meilleure pratique consistait à effectuer une initialisation coûteuse danssetUp
, qui n'était exécutée que lorsque le test était exécuté. Cela ne s'applique plus, il est donc beaucoup moins nécessaire de l'utilisersetUp
.Ceci résume plusieurs autres réponses qui enterrent la lede, notamment par Craig P. Motlin (question elle-même et auto-réponse), Moss Collum (classe sous test), et dsaff.
la source
Dans JUnit 3, vos initialiseurs de champ seront exécutés une fois par méthode de test avant que les tests ne soient exécutés . Tant que vos valeurs de champ sont petites en mémoire, prennent peu de temps de configuration et n'affectent pas l'état global, l'utilisation des initialiseurs de champ est techniquement très bien. Cependant, si ceux-ci ne tiennent pas, vous pouvez finir par consommer beaucoup de mémoire ou de temps à configurer vos champs avant le premier test, et peut-être même manquer de mémoire. Pour cette raison, de nombreux développeurs définissent toujours des valeurs de champ dans la méthode setUp (), où elle est toujours sûre, même si ce n'est pas strictement nécessaire.
Notez que dans JUnit 4, l'initialisation des objets de test se produit juste avant l'exécution du test, et donc l'utilisation d'initialiseurs de champ est un style plus sûr et recommandé.
la source
Dans votre cas (création d'une liste), il n'y a pas de différence dans la pratique. Mais en général, il est préférable d'utiliser setUp (), car cela aidera Junit à signaler correctement les exceptions. Si une exception se produit dans le constructeur / initialiseur d'un test, c'est un échec du test . Cependant, si une exception se produit lors de la configuration, il est naturel de la considérer comme un problème lors de la configuration du test, et junit le signale de manière appropriée.
la source
Je préfère d'abord la lisibilité qui n'utilise le plus souvent pas la méthode de configuration. Je fais une exception lorsqu'une opération de configuration de base prend beaucoup de temps et est répétée dans chaque test.
À ce stade, je déplace cette fonctionnalité dans une méthode de configuration à l'aide de l'
@BeforeClass
annotation (optimisez plus tard).Exemple d'optimisation utilisant la
@BeforeClass
méthode de configuration: J'utilise dbunit pour certains tests fonctionnels de base de données. La méthode de configuration est chargée de mettre la base de données dans un état connu (très lent ... 30 secondes - 2 minutes selon la quantité de données). Je charge ces données dans la méthode de configuration annotée avec@BeforeClass
, puis j'exécute 10 à 20 tests sur le même ensemble de données au lieu de recharger / initialiser la base de données à l'intérieur de chaque test.Utiliser Junit 3.8 (étendre TestCase comme indiqué dans votre exemple) nécessite d'écrire un peu plus de code que d'ajouter simplement une annotation, mais le "exécuter une fois avant la configuration de la classe" est toujours possible.
la source
Étant donné que chaque test est exécuté indépendamment, avec une nouvelle instance de l'objet, il n'y a pas grand intérêt à ce que l'objet Test ait un état interne à l'exception de celui partagé entre
setUp()
et un test individuel ettearDown()
. C'est une des raisons (en plus des raisons données par d'autres) pour laquelle il est bon d'utiliser lasetUp()
méthode.Remarque: C'est une mauvaise idée pour un objet de test JUnit de maintenir l'état statique! Si vous utilisez une variable statique dans vos tests pour autre chose que le suivi ou le diagnostic, vous invalidez une partie de l'objectif de JUnit, qui est que les tests peuvent (et peuvent) être exécutés dans n'importe quel ordre, chaque test s'exécutant avec un état frais et propre.
Les avantages de l'utilisation
setUp()
sont que vous n'avez pas à copier-coller le code d'initialisation dans chaque méthode de test et que vous n'avez pas de code de configuration de test dans le constructeur. Dans votre cas, il y a peu de différence. Créer simplement une liste vide peut être fait en toute sécurité lorsque vous l'affichez ou dans le constructeur car il s'agit d'une initialisation triviale. Cependant, comme vous et d'autres l'avez souligné, tout ce qui peut éventuellement générer unException
doit être faitsetUp()
afin d'obtenir le vidage de la pile de diagnostic en cas d'échec.Dans votre cas, où vous créez simplement une liste vide, je ferais de la même manière que vous suggérez: Attribuez la nouvelle liste au point de déclaration. Surtout parce que de cette façon vous avez la possibilité de le marquer
final
si cela a du sens pour votre classe de test.la source
final
est cependant mentionné dans la question.Les valeurs constantes (utilisations dans les fixtures ou les assertions) doivent être initialisées dans leurs déclarations et
final
(comme ne changent jamais)l'objet testé doit être initialisé dans la méthode de configuration car nous pouvons activer les choses. Bien sûr, nous ne pouvons pas définir quelque chose maintenant, mais nous pourrions le définir plus tard. L'instanciation dans la méthode init faciliterait les modifications.
dépendances de l'objet testé si celles-ci sont moquées, ne doivent même pas être instanciées par vous-même: aujourd'hui, les frameworks fictifs peuvent l'instancier par réflexion.
Un test sans dépendance à simuler pourrait ressembler à:
Un test avec des dépendances à isoler pourrait ressembler à ceci:
la source