2009-09-19 14 views
2

Dans une classe de test, je voudrais fournir ma propre surcharge de assertEquals avec une logique spéciale ne comptant pas sur Object.equals. Malheureusement, cela ne fonctionne pas car dès que je déclare ma méthode assertEquals en local, Java ne trouve plus l'importation statique de org.junit.Assert.*.Surcharge statiques importations

Y a-t-il un moyen de contourner cela? C'est à dire. existe-t-il un moyen de fournir une surcharge supplémentaire à une méthode importée statiquement? (La solution plutôt évidente étant de nommer différemment la méthode, mais cette solution n'a pas le même attrait esthétique.)

Mon fichier de classe de test ressemble à quelque chose comme ceci:

package org.foo.bar; 

import static org.junit.Assert.*; 

import org.junit.Test; 

public class BarTest { 
    private static void assertEquals(Bar expected, Bar other) { 
     // Some custom logic to test equality. 
    } 

    @Test 
    public void testGetFoo() throws Exception { 
     Bar a = new Bar(); 
     assertEquals(42, a.getFoo()); // Error * 
    } 

    @Test 
    public void testCopyConstructor() throws Exception { 
     Bar a = new Bar(); 
     // Fill a. 
     Bar b = new Bar(a); 
     assertEquals(a, b); 
    } 
} 

Error * est « La méthode assertEquals(Bar, Bar) dans le type BarTest n'est pas applicable pour les arguments (int, int). "

+0

Quel est le type de retour de getFoo() dans la classe Bar - int ou autre? –

+0

Peu importe, compris que c'était int via le message d'erreur. –

+5

Ce n'est pas une réponse directe, mais je mettrais vraiment en doute votre motivation pour ce faire, l '"appel esthétique" comme vous le dites. Si je suis un développeur qui lit un test unitaire, je veux que assertEquals soit toujours l'implémentation de JUnit. En utilisant la méthode assertBarEquals est beaucoup plus communicative à mon avis. C'est une question valide, et je pourrais voir comment cela pourrait être utile dans d'autres situations, je ne crois tout simplement pas qu'un autre moyen bat assertBarEquals(). – Grundlefleck

Répondre

3

Il y a deux sections dans cette réponse - une sur l'erreur de compilation, et l'autre sur l'utilisation de assertEquals()

Le problème est que les méthodes il y a deux assertEquals() dans deux espaces de noms différents - un présent dans l'espace de noms org.junit.Assert, l'autre dans l'espace de noms org.foo.bar.BarTest (l'espace de noms courant). L'erreur est signalée par le compilateur en raison du shadowing rules declared in the Java Language Specification. L'importation statique de Assert.assertEquals() est ombrée par le assertEquals() déclaré dans la classe BarTest.

Le correctif (toujours dans le cas des déclarations ombrées) consiste à utiliser des noms FQN (Fully Qualified Names). Si vous avez l'intention d'utiliser assertEquals (...) de la classe JUnit Assertion, utilisez

org.junit.Assert.assertEquals(...) 

et quand vous devez utiliser votre déclaration utilisez simplement

assertEquals(...) 

dans BarTest seulement, où il est occulté . Dans toutes les autres classes qui ne nécessitent que Assert.assertEquals() ou BarTest.asserEquals(), vous pouvez importer Assert ou BarTest (je ne pense pas que vous auriez besoin d'importer BarTest ailleurs, mais l'ai quand même déclaré). En l'absence d'observation, vous pouvez simplement importer la méthode de classe ou statique et l'utiliser sans FQN.

choses supplémentaires à penser à

Assert.assertEquals() utilise en interne la méthode equals() des classes des arguments. Déclarer un assertEquals() dans votre cas de test, viole le principe DRY, puisque la méthode de type equals() doit être implémentée et utilisée de manière cohérente - mettre deux implémentations différentes dans le code source et provoquer des confusions dans les tests unitaires. La meilleure approche serait d'implémenter equals() sur Bar, puis d'utiliser Assert.assertEquals() dans vos cas de test. Si vous avez déjà, vous n'avez pas besoin d'un BarTest.assertEquals().Le pseudocode pour assertEquals() est un peu comme le suivant

  1. Si les deux arguments sont NULL, retourner vrai.
  2. Si prévu est non nul, alors invoquer equals() sur prévu passant la réelle comme argument. Retourne vrai si l'objet est égal.
  3. Si les objets ne sont pas égaux, lancez AssertionError avec un message formaté.
+0

Je ne pense pas vraiment que cela viole DRY (plutôt POLS, puisque nous utilisons des acronymes): 'equal 'n'existe pas intentionnellement sur mon type car cela n'a absolument aucun sens que ces types soient égaux comparables - sauf pour ce test unitaire - donc ils ne l'appliquent pas. –

+0

Une situation délicate, qui rend discutable la nécessité d'avoir une implémentation equals() ou d'asservir assertEquals(). J'irais avec equals(). –

1

La seule façon est de qualifier pleinement l'un ou l'autre.

import static org.junit.Assert.*; 

import org.junit.Test; 

public class BarTest { 

    private static void assertEquals(Bar expected, Bar other) { 
     // Some custom logic to test equality. 
    } 

    @Test 
    public void testGetFoo() throws Exception { 
     Bar a = new Bar(); 
     org.junit.Assert.assertEquals(42, a.getFoo()); 
    } 
} 
3

Une solution possible pour votre exemple spécifique d'appeler assertEquals(Bar, Bar) dans un test unitaire serait d'étendre la classe avec celle qui fournit la méthode statique, comme suit:

class BarAssert extends Assert { 
    public static void assertEquals(Bar expected, Bar other) { 
     // Some custom logic to test equality. 
    } 
} 

Vous pouvez ensuite inclure import static BarAssert.assertEquals; et utilisez votre logique personnalisée. Désolé, cela ne répond pas directement à la question, et est plus axé sur votre exemple. Selon mon commentaire joint à la question, je recommanderais de ne pas adopter cette approche.

+0

+1. Toute personne lisant ceci et utilisant cette approche devrait également lancer AssertionError en cas d'échec. Les coureurs d'essai seraient alors en mesure de marquer un test raté en rouge. –

+0

Ce serait java.lang.AssertionError http://java.sun.com/j2se/1.5.0/docs/api/java/lang/AssertionError.html –

+0

@Vineet: pourquoi ne pas simplement utiliser 'Assert.fail'? –

0
this.assertEquals(a,b); 

ou

BarTest.assertEquals(a,b); 

je partirais avec le premier, car bien qu'il soit une méthode statique, vous devez avoir une instance pour l'utiliser (il est privé) et this won Ne soyez pas soumis à la fantaisie de renamings futurs.