Eu sou novo em testes de Java com JUnit. Tenho que trabalhar com Java e gostaria de usar testes de unidade.
Meu problema é: eu tenho uma classe abstrata com alguns métodos abstratos. Mas existem alguns métodos que não são abstratos. Como posso testar esta classe com JUnit? Código de exemplo (muito simples):
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;
}
}
Eu quero testar getSpeed()
e getFuel()
funções.
Uma questão semelhante a este problema é aqui , mas não está usando JUnit.
Na seção JUnit FAQ, encontrei este link , mas não entendo o que o autor quer dizer com este exemplo. O que essa linha de código significa?
public abstract Source getSource() ;
java
junit
abstract-class
vasco
fonte
fonte
Respostas:
Se você não tem implementações concretas da classe e os métodos não são
static
que testá-los? Se você tiver uma classe concreta, então testará esses métodos como parte da API pública da classe concreta.Eu sei o que você está pensando "Não quero testar esses métodos repetidamente, por isso criei a classe abstrata", mas meu contra-argumento é que o objetivo dos testes de unidade é permitir que os desenvolvedores façam alterações, execute os testes e analise os resultados. Parte dessas mudanças pode incluir a substituição dos métodos de sua classe abstrata, ambos
protected
epublic
, o que pode resultar em mudanças comportamentais fundamentais. Dependendo da natureza dessas alterações, isso pode afetar o modo como seu aplicativo é executado de maneiras inesperadas e possivelmente negativas. Se você tiver um bom conjunto de testes de unidade, os problemas decorrentes desses tipos de alterações devem ser aparentes no momento do desenvolvimento.fonte
final
? Não vejo razão para testar o mesmo método várias vezes se a implementação não puder ser alteradaCrie uma classe concreta que herde a classe abstrata e teste as funções que a classe concreta herda da classe abstrata.
fonte
Com a aula de exemplo que você postou, não parece fazer muito sentido testar
getFuel()
egetSpeed()
uma vez que eles podem retornar apenas 0 (não há setters).No entanto, presumindo que este foi apenas um exemplo simplificado para fins ilustrativos, e que você tem motivos legítimos para testar métodos na classe base abstrata (outros já apontaram as implicações), você pode configurar seu código de teste para que crie um código anônimo subclasse da classe base que apenas fornece implementações fictícias (não operacionais) para os métodos abstratos.
Por exemplo, no seu,
TestCase
você pode fazer o seguinte:c = new Car() { void drive() { }; };
Em seguida, teste o restante dos métodos, por exemplo:
public class CarTest extends TestCase { private Car c; public void setUp() { c = new Car() { void drive() { }; }; } public void testGetFuel() { assertEquals(c.getFuel(), 0); } [...] }
(Este exemplo é baseado na sintaxe JUnit3. Para JUnit4, o código seria um pouco diferente, mas a ideia é a mesma.)
fonte
Se você precisa de uma solução de qualquer maneira (por exemplo, porque você tem muitas implementações da classe abstrata e os testes sempre repetem os mesmos procedimentos), então você pode criar uma classe de teste abstrata com um método de fábrica abstrato que será executado pela implementação daquele classe de teste. Este exemplo funciona para mim com TestNG:
A classe de teste abstrata 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); ...
Implementação de
Car
class ElectricCar extends Car { private final int batteryCapacity; public ElectricCar(int speed, int fuel, int batteryCapacity) { super(speed, fuel); this.batteryCapacity = batteryCapacity; } ...
Aula
ElectricCarTest
de teste de unidade da 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 ...
fonte
Você poderia fazer algo assim
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); } }
fonte
Eu criaria uma classe interna jUnit que herda da classe abstrata. Isso pode ser instanciado e ter acesso a todos os métodos definidos na classe abstrata.
public class AbstractClassTest { public void testMethod() { ... } } class ConcreteClass extends AbstractClass { }
fonte
Você pode instanciar uma classe anônima e, em seguida, testar essa 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); } }
Lembre-se de que a visibilidade deve ser
protected
para a propriedademyDependencyService
da classe abstrataClassUnderTest
.Você também pode combinar essa abordagem perfeitamente com o Mockito. Veja aqui .
fonte
Minha maneira de testar isso é bastante simples, dentro de cada um
abstractUnitTest.java
. Eu simplesmente crio uma classe no abstractUnitTest.java que estende a classe abstrata. E teste dessa forma.fonte
Você não pode testar uma classe abstrata inteira. Nesse caso, você tem métodos abstratos, isso significa que eles devem ser implementados por classes que estendem a classe abstrata dada.
Nessa classe o programador tem que escrever o código-fonte que é dedicado à lógica dele.
Em outras palavras, não há sentido em testar uma classe abstrata porque você não é capaz de verificar o comportamento final dela.
Se você tiver uma funcionalidade principal não relacionada a métodos abstratos em alguma classe abstrata, apenas crie outra classe onde o método abstrato irá lançar alguma exceção.
fonte
Como opção, você pode criar uma classe de teste abstrata cobrindo a lógica dentro da classe abstrata e estendê-la para cada teste de subclasse. Para que desta forma você possa garantir que essa lógica será testada para cada criança separadamente.
fonte