web-dev-qa-db-fra.com

JUnit: utiliser le constructeur au lieu de @Before

J'utilise JUnit 4. Je ne vois pas la différence entre l'initialisation dans le constructeur et l'utilisation d'une fonction init dédiée annotée par @Before. Est-ce que cela signifie que je n'ai pas à m'inquiéter?

Existe-t-il un cas où @Before donne plus que l'initialisation dans le constructeur?

61
vbence

Non, utiliser le constructeur pour initialiser votre appareil de test JUnit est techniquement équivalent à utiliser la méthode @Before (en raison du fait que JUnit crée une nouvelle instance de la classe de test pour chaque @Test). La seule différence (connotative) est que cela brise la symétrie entre @Before et @After, ce qui peut être déroutant pour certains. IMHO il est préférable de respecter les conventions (qui utilise @Before).

Notez également qu'avant JUnit 4 et les annotations, il existait des méthodes dédiées setUp() et tearDown(); les annotations @Before et @After les remplacent, tout en préservant la logique sous-jacente. Par conséquent, l’utilisation des annotations facilite également la tâche de ceux qui migrent depuis JUnit 3 ou des versions antérieures.

Différences notables

Plus de détails à partir des commentaires:

  • @Before permet de redéfinir le comportement de la classe parent, les constructeurs vous forçant à appeler les constructeurs de la classe parent
  • Le constructeur exécute before constructeurs de sous-classe et méthodes @Rule, @Before exécute after tous ceux
  • Les exceptions lors de @Before entraînent l'appel de méthodes @After, les exceptions dans le constructeur ne le font pas
74
Péter Török

@Before est plus logique à utiliser dans certains cas car il est appelé APRÈS le constructeur de la classe. Cette différence est importante lorsque vous utilisez un framework fictif tel que Mockito avec des annotations @Mock, car votre méthode @Before sera appelée après l'initialisation des simulations. Vous pouvez ensuite utiliser vos modèles pour fournir des arguments de constructeur à la classe sous test.

Je trouve ce schéma très courant dans mes tests unitaires lors de l’utilisation de beans collaborateurs.

Voici un exemple (certes artificiel):

@RunWith(MockitoJUnitRunner.class)
public class CalculatorTest {
    @Mock Adder adder;
    @Mock Subtractor subtractor;
    @Mock Divider divider;
    @Mock Multiplier multiplier;

    Calculator calculator;

    @Before
    public void setUp() {
        calculator = new Calculator(adder,subtractor,divider,multiplier);
    }

    @Test
    public void testAdd() {
        BigDecimal value = calculator.add(2,2);
        verify(adder).add(eq(2),eq(2));
    }
}
25
HopefullyHelpful

Je préfère utiliser des constructeurs pour initialiser mes objets de test, car cela me permet de rendre tous les membres final afin que le IDE ou le compilateur me dise quand le constructeur a oublié d'initialiser un membre et empêche une autre méthode de les mettre.

IMHO, @Before enfreint l'une des conventions les plus importantes de Java, celle de s'appuyer sur le constructeur pour initaliser complètement les objets!

6
Derek Mahar

Je préfère déclarer mes appareils comme finaux et les initialiser en ligne ou dans le constructeur, alors je n'oublie pas de les initialiser! Cependant, comme les exceptions générées dans @Before sont gérées de manière plus conviviale, j’initialise habituellement l’objet à tester dans @Before.

5
thSoft

Il y a une chose que constructeur peut archiver mais pas @Avant .

Vous devez utiliser un constructeur lorsque vous devez initialiser les champs définis dans la classe parente. Par exemple:

abstract class AbstractIT {
   int fieldAssignedInSubClass;
   public AbstractIT(int fieldAssignedInSubClass) {
      this.fieldAssignedInSubClass= fieldAssignedInSubClass;
   }

   @Before
   void before() {
      // comsume fieldAssignedInSubClass
   } 
}

public class ChildIT extends AbstractIT{
   public ChildIT() {
      // assign fieldAssignedInSubClass by constructor
      super(5566); 
   }

   @Before
   void before() {
      // you cannot assign fieldAssignedInSubClass by a @Before method
   } 
}
1
okwap

@Before est invoqué avant tout @Test et pas seulement une fois par Test-Class.
Ceci peut être utilisé pour réinitialiser/initialiser les données pour chaque test spécifique (comme réinitialiser les variables à une valeur spécifique, etc.).

Dans le même mode, @After peut être utilisé pour nettoyer le code après l'exécution d'une méthode @Test.

Voir: http://junit.sourceforge.net/javadoc/org/junit/Before.html

1
oers

Citation de http://etutorials.org/Programming/Java+extreme+programming/Chapter+4.+JUnit/4.6+Set+Up+and+Tear+Down/

Vous vous demandez peut-être pourquoi vous devriez écrire une méthode setUp () au lieu de initialiser simplement les champs dans le constructeur d'un cas de test. Après tout, puisqu’une nouvelle instance du scénario de test est créée pour chacun de ses tests méthodes, le constructeur est toujours appelé avant setUp (). Dans un vaste Dans la majorité des cas, vous pouvez utiliser le constructeur à la place de setUp () sans aucun effet secondaire.

Dans les cas où votre cas de test fait partie d'un héritage plus profond hiérarchie, vous souhaiterez peut-être différer l’initialisation de l’objet jusqu’à les instances de classes dérivées sont entièrement construites. C'est un bon raison technique pour laquelle vous voudrez peut-être utiliser setUp () au lieu de constructeur pour l'initialisation. Utiliser setUp () et tearDown () est aussi bon pour la documentation, simplement parce que cela peut rendre le code plus facile à lire.

1
IqbalHamid

@Before est logique à utiliser pour plusieurs raisons. Cela rend votre code de test plus lisible. Il correspond à l'annotation @After qui est responsable de la libération des ressources utilisées et est l'homologue de l'annotation @BeforeClass.

0
Boris Pavlović

Il n'y a pas de différence sauf que le constructeur est la seule méthode permettant d'initialiser les objets @Rule:

public class TestClass {

    @Rule
    public SomeRule rule;

    public TestClass() {
        // code to initialize the rule field
        conf = new RuleConf()
        rule = new SomeRule(conf)
    }
}
0
ayun12