Soy nuevo en las pruebas de Java con JUnit. Tengo que trabajar con Java y me gustaría usar pruebas unitarias.
Mi problema es: tengo una clase abstracta con algunos métodos abstractos. Pero hay algunos métodos que no son abstractos. ¿Cómo puedo probar esta clase con JUnit? Código de ejemplo (muy 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;
}
}
Quiero probar getSpeed()
y getFuel()
funciones.
Aquí hay una pregunta similar a este problema , pero no está usando JUnit.
En la sección de preguntas frecuentes de JUnit, encontré este enlace , pero no entiendo lo que el autor quiere decir con este ejemplo. ¿Qué significa esta línea de código?
public abstract Source getSource() ;
java
junit
abstract-class
vasco
fuente
fuente
Respuestas:
Si no tiene implementaciones concretas de la clase y los métodos no son,
static
¿cuál es el punto de probarlos? Si tiene una clase concreta, probará esos métodos como parte de la API pública de la clase concreta.Sé lo que estás pensando "No quiero probar estos métodos una y otra vez, esa es la razón por la que creé la clase abstracta", pero mi argumento en contra es que el objetivo de las pruebas unitarias es permitir que los desarrolladores realicen cambios, ejecutar las pruebas y analizar los resultados. Parte de esos cambios podrían incluir anular los métodos de su clase abstracta, tanto
protected
ypublic
, lo que podría resultar en cambios fundamentales de comportamiento. Dependiendo de la naturaleza de esos cambios, podría afectar la forma en que se ejecuta su aplicación de formas inesperadas, posiblemente negativas. Si tiene un buen conjunto de pruebas unitarias, los problemas derivados de estos tipos de cambios deberían ser evidentes en el momento del desarrollo.fuente
final
? No veo una razón para probar el mismo método varias veces si la implementación no puede cambiarCree una clase concreta que herede la clase abstracta y luego pruebe las funciones que la clase concreta hereda de la clase abstracta.
fuente
Con la clase de ejemplo que publicó, no parece tener mucho sentido probar
getFuel()
ygetSpeed()
dado que solo pueden devolver 0 (no hay establecedores).Sin embargo, suponiendo que este sea solo un ejemplo simplificado con fines ilustrativos, y que tenga razones legítimas para probar métodos en la clase base abstracta (otros ya han señalado las implicaciones), puede configurar su código de prueba para que cree un anónimo subclase de la clase base que solo proporciona implementaciones ficticias (no operativas) para los métodos abstractos.
Por ejemplo, en tu
TestCase
podrías hacer esto:c = new Car() { void drive() { }; };
Luego pruebe el resto de los métodos, por ejemplo:
public class CarTest extends TestCase { private Car c; public void setUp() { c = new Car() { void drive() { }; }; } public void testGetFuel() { assertEquals(c.getFuel(), 0); } [...] }
(Este ejemplo se basa en la sintaxis de JUnit3. Para JUnit4, el código sería ligeramente diferente, pero la idea es la misma).
fuente
Si necesita una solución de todos modos (por ejemplo, porque tiene demasiadas implementaciones de la clase abstracta y las pruebas siempre repetirían los mismos procedimientos), entonces podría crear una clase de prueba abstracta con un método de fábrica abstracto que será ejecutado por la implementación de ese clase de prueba. Este ejemplo funciona para mí con TestNG:
La clase de prueba abstracta 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); ...
Implementación de
Car
class ElectricCar extends Car { private final int batteryCapacity; public ElectricCar(int speed, int fuel, int batteryCapacity) { super(speed, fuel); this.batteryCapacity = batteryCapacity; } ...
Clase
ElectricCarTest
de prueba unitaria de la ClaseElectricCar
: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 ...
fuente
Podrías hacer algo como esto
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); } }
fuente
Crearía una clase interna jUnit que hereda de la clase abstracta. Esto se puede instanciar y tener acceso a todos los métodos definidos en la clase abstracta.
public class AbstractClassTest { public void testMethod() { ... } } class ConcreteClass extends AbstractClass { }
fuente
Puede crear una instancia de una clase anónima y luego probar esa clase.
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); } }
Tenga en cuenta que la visibilidad debe ser
protected
para la propiedadmyDependencyService
de la clase abstractaClassUnderTest
.También puede combinar este enfoque perfectamente con Mockito. Vea aquí .
fuente
Mi forma de probar esto es bastante simple, dentro de cada uno
abstractUnitTest.java
. Simplemente creo una clase en abstractUnitTest.java que amplía la clase abstracta. Y pruébalo de esa manera.fuente
No puedes probar toda la clase abstracta. En este caso, tiene métodos abstractos, esto significa que deben ser implementados por una clase que amplíe la clase abstracta dada.
En esa clase el programador tiene que escribir el código fuente que se dedica a su lógica.
En otras palabras, no tiene sentido probar la clase abstracta porque no puede verificar el comportamiento final de la misma.
Si tiene una funcionalidad importante no relacionada con los métodos abstractos en alguna clase abstracta, simplemente cree otra clase donde el método abstracto arrojará alguna excepción.
fuente
Como opción, puede crear una clase de prueba abstracta que cubra la lógica dentro de la clase abstracta y extenderla para cada prueba de subclase. Para que de esta manera pueda asegurarse de que esta lógica se probará para cada niño por separado.
fuente