Je suis nouveau dans les tests Java avec JUnit. Je dois travailler avec Java et j'aimerais utiliser des tests unitaires.
Mon problème est: j'ai une classe abstraite avec des méthodes abstraites. Mais il existe des méthodes qui ne sont pas abstraites. Comment puis-je tester cette classe avec JUnit? Exemple de code (très simple):
abstract class Car {
public Car(int speed, int fuel) {
this.speed = speed;
this.fuel = fuel;
}
private int speed;
private int fuel;
abstract void drive();
public int getSpeed() {
return this.speed;
}
public int getFuel() {
return this.fuel;
}
}
Je veux tester getSpeed()
et getFuel()
fonctionner.
Une question similaire à ce problème est ici , mais elle n'utilise pas JUnit.
Dans la section FAQ de JUnit, j'ai trouvé ce lien , mais je ne comprends pas ce que l'auteur veut dire avec cet exemple. Que signifie cette ligne de code?
public abstract Source getSource() ;
java
junit
abstract-class
Vasco
la source
la source
Réponses:
Si vous n'avez pas d'implémentations concrètes de la classe et que les méthodes ne servent pas à
static
les tester? Si vous avez une classe concrète, vous testerez ces méthodes dans le cadre de l'API publique de la classe concrète.Je sais ce que vous pensez "Je ne veux pas tester ces méthodes encore et encore, c'est la raison pour laquelle j'ai créé la classe abstraite", mais mon contre-argument est que le but des tests unitaires est de permettre aux développeurs d'apporter des modifications, exécutez les tests et analysez les résultats. Une partie de ces changements pourrait inclure le remplacement des méthodes de votre classe abstraite, à la fois
protected
etpublic
, ce qui pourrait entraîner des changements de comportement fondamentaux. En fonction de la nature de ces modifications, cela peut affecter la manière dont votre application s'exécute de manière inattendue, voire négative. Si vous avez une bonne suite de tests unitaires, les problèmes résultant de ces types de modifications devraient être apparents au moment du développement.la source
final
? Je ne vois pas de raison de tester la même méthode plusieurs fois si la mise en œuvre ne peut pas changerCréez une classe concrète qui hérite de la classe abstraite, puis testez les fonctions que la classe concrète hérite de la classe abstraite.
la source
Avec l'exemple de classe que vous avez posté, il ne semble pas logique de tester
getFuel()
etgetSpeed()
puisqu'ils ne peuvent renvoyer que 0 (il n'y a pas de setters).Cependant, en supposant qu'il ne s'agissait que d'un exemple simplifié à des fins d'illustration, et que vous ayez des raisons légitimes de tester des méthodes dans la classe de base abstraite (d'autres ont déjà souligné les implications), vous pouvez configurer votre code de test de sorte qu'il crée un sous-classe de la classe de base qui fournit simplement des implémentations factices (sans opération) pour les méthodes abstraites.
Par exemple, dans votre,
TestCase
vous pouvez faire ceci:c = new Car() { void drive() { }; };
Ensuite, testez le reste des méthodes, par exemple:
public class CarTest extends TestCase { private Car c; public void setUp() { c = new Car() { void drive() { }; }; } public void testGetFuel() { assertEquals(c.getFuel(), 0); } [...] }
(Cet exemple est basé sur la syntaxe JUnit3. Pour JUnit4, le code serait légèrement différent, mais l'idée est la même.)
la source
Si vous avez quand même besoin d'une solution (par exemple parce que vous avez trop d'implémentations de la classe abstraite et que les tests répéteraient toujours les mêmes procédures), vous pouvez créer une classe de test abstraite avec une méthode de fabrique abstraite qui sera exécutée par l'implémentation de cette classe de test. Cet exemple fonctionne ou moi avec TestNG:
La classe de test abstraite de
Car
:abstract class CarTest { // the factory method abstract Car createCar(int speed, int fuel); // all test methods need to make use of the factory method to create the instance of a car @Test public void testGetSpeed() { Car car = createCar(33, 44); assertEquals(car.getSpeed(), 33); ...
Implémentation de
Car
class ElectricCar extends Car { private final int batteryCapacity; public ElectricCar(int speed, int fuel, int batteryCapacity) { super(speed, fuel); this.batteryCapacity = batteryCapacity; } ...
Classe
ElectricCarTest
de test unitaire de la classeElectricCar
:class ElectricCarTest extends CarTest { // implementation of the abstract factory method Car createCar(int speed, int fuel) { return new ElectricCar(speed, fuel, 0); } // here you cann add specific test methods ...
la source
Tu pourrais faire quelque chose comme ça
public abstract MyAbstractClass { @Autowire private MyMock myMock; protected String sayHello() { return myMock.getHello() + ", " + getName(); } public abstract String getName(); } // this is your JUnit test public class MyAbstractClassTest extends MyAbstractClass { @Mock private MyMock myMock; @InjectMocks private MyAbstractClass thiz = this; private String myName = null; @Override public String getName() { return myName; } @Test public void testSayHello() { myName = "Johnny" when(myMock.getHello()).thenReturn("Hello"); String result = sayHello(); assertEquals("Hello, Johnny", result); } }
la source
Je créerais une classe interne jUnit qui hérite de la classe abstraite. Cela peut être instancié et avoir accès à toutes les méthodes définies dans la classe abstraite.
public class AbstractClassTest { public void testMethod() { ... } } class ConcreteClass extends AbstractClass { }
la source
Vous pouvez instancier une classe anonyme, puis tester cette classe.
public class ClassUnderTest_Test { private ClassUnderTest classUnderTest; private MyDependencyService myDependencyService; @Before public void setUp() throws Exception { this.myDependencyService = new MyDependencyService(); this.classUnderTest = getInstance(); } private ClassUnderTest getInstance() { return new ClassUnderTest() { private ClassUnderTest init( MyDependencyService myDependencyService ) { this.myDependencyService = myDependencyService; return this; } @Override protected void myMethodToTest() { return super.myMethodToTest(); } }.init(myDependencyService); } }
Gardez à l'esprit que la visibilité doit
protected
concerner la propriétémyDependencyService
de la classe abstraiteClassUnderTest
.Vous pouvez également combiner parfaitement cette approche avec Mockito. Regardez ici .
la source
Ma façon de tester cela est assez simple, dans chacun d'eux
abstractUnitTest.java
. Je crée simplement une classe dans abstractUnitTest.java qui étend la classe abstraite. Et testez-le de cette façon.la source
Vous ne pouvez pas tester toute la classe abstraite. Dans ce cas, vous avez des méthodes abstraites, cela signifie qu'elles doivent être implémentées par une classe qui étend une classe abstraite donnée.
Dans cette classe, le programmeur doit écrire le code source qui est dédié à sa logique.
En d'autres termes, il n'y a aucun sens de tester une classe abstraite parce que vous n'êtes pas en mesure d'en vérifier le comportement final.
Si vous avez des fonctionnalités majeures non liées aux méthodes abstraites dans une classe abstraite, créez simplement une autre classe où la méthode abstraite lèvera une exception.
la source
En option, vous pouvez créer une classe de test abstraite couvrant la logique à l'intérieur d'une classe abstraite et l'étendre pour chaque test de sous-classe. Ainsi, vous pouvez vous assurer que cette logique sera testée séparément pour chaque enfant.
la source