Я новичок в тестировании Java с помощью JUnit. Мне нужно работать с Java, и я хотел бы использовать модульные тесты.
Моя проблема: у меня есть абстрактный класс с некоторыми абстрактными методами. Но есть методы, которые не являются абстрактными. Как я могу протестировать этот класс с помощью JUnit? Пример кода (очень простой):
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;
}
}
Хочу протестировать getSpeed()
и getFuel()
функции.
Аналогичный вопрос к этой проблеме здесь , но он не использует JUnit.
В разделе часто задаваемых вопросов JUnit я нашел эту ссылку , но не понимаю, что автор хочет сказать этим примером. Что означает эта строка кода?
public abstract Source getSource() ;
java
junit
abstract-class
васко
источник
источник
Ответы:
Если у вас нет конкретных реализаций класса и методы не имеют
static
смысла их тестировать? Если у вас есть конкретный класс, вы будете тестировать эти методы как часть общедоступного API конкретного класса.Я знаю, что вы думаете: «Я не хочу тестировать эти методы снова и снова, поэтому я создал абстрактный класс», но мой контраргумент заключается в том, что суть модульных тестов заключается в том, чтобы позволить разработчикам вносить изменения, запустить тесты и проанализировать результаты. Частично эти изменения могут включать переопределение методов вашего абстрактного класса, как
protected
иpublic
, что может привести к фундаментальным изменениям в поведении. В зависимости от характера этих изменений это может повлиять на работу вашего приложения неожиданными, возможно, отрицательными способами. Если у вас есть хороший комплект модульного тестирования, проблемы, возникающие из-за изменений этих типов, должны быть очевидны во время разработки.источник
final
? Я не вижу причин для тестирования одного и того же метода несколько раз, если реализация не может изменитьсяСоздайте конкретный класс, который наследует абстрактный класс, а затем проверьте функции, которые конкретный класс наследует от абстрактного класса.
источник
В примере класса, который вы опубликовали, похоже, нет смысла тестировать,
getFuel()
иgetSpeed()
поскольку они могут возвращать только 0 (нет сеттеров).Однако, предполагая, что это был просто упрощенный пример для иллюстративных целей и что у вас есть законные причины для тестирования методов в абстрактном базовом классе (другие уже указали на последствия), вы можете настроить свой тестовый код так, чтобы он создавал анонимный подкласс базового класса, который просто предоставляет фиктивные (безоперационные) реализации абстрактных методов.
Например, в вашем
TestCase
вы можете сделать это:c = new Car() { void drive() { }; };
Затем проверьте остальные методы, например:
public class CarTest extends TestCase { private Car c; public void setUp() { c = new Car() { void drive() { }; }; } public void testGetFuel() { assertEquals(c.getFuel(), 0); } [...] }
(Этот пример основан на синтаксисе JUnit3. Для JUnit4 код будет немного другим, но идея та же.)
источник
Если вам все равно нужно решение (например, потому что у вас слишком много реализаций абстрактного класса и тестирование всегда будет повторять одни и те же процедуры), вы можете создать абстрактный тестовый класс с абстрактным фабричным методом, который будет выполняться реализацией этого тестовый класс. Эти примеры работают или я с TestNG:
Абстрактный тестовый класс
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); ...
Реализация
Car
class ElectricCar extends Car { private final int batteryCapacity; public ElectricCar(int speed, int fuel, int batteryCapacity) { super(speed, fuel); this.batteryCapacity = batteryCapacity; } ...
Модульный тестовый класс
ElectricCarTest
КлассаElectricCar
: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 ...
источник
Вы могли бы сделать что-то вроде этого
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); } }
источник
Я бы создал внутренний класс jUnit, унаследованный от абстрактного класса. Он может быть создан и иметь доступ ко всем методам, определенным в абстрактном классе.
public class AbstractClassTest { public void testMethod() { ... } } class ConcreteClass extends AbstractClass { }
источник
Вы можете создать экземпляр анонимного класса, а затем протестировать этот класс.
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); } }
Имейте в виду, что видимость должна быть
protected
для свойстваmyDependencyService
абстрактного классаClassUnderTest
.Вы также можете аккуратно комбинировать этот подход с Mockito. Смотрите здесь .
источник
Мой способ проверить это довольно просто, в каждом
abstractUnitTest.java
. Я просто создаю класс в abstractUnitTest.java, который расширяет абстрактный класс. И протестируйте это таким образом.источник
Вы не можете протестировать весь абстрактный класс. В этом случае у вас есть абстрактные методы, это означает, что они должны быть реализованы классом, расширяющим данный абстрактный класс.
В этом классе программист должен написать исходный код, предназначенный для его логики.
Другими словами, нет смысла тестировать абстрактный класс, потому что вы не можете проверить его окончательное поведение.
Если у вас есть основные функции, не связанные с абстрактными методами в каком-то абстрактном классе, просто создайте другой класс, в котором абстрактный метод вызовет какое-то исключение.
источник
Как вариант, вы можете создать абстрактный тестовый класс, охватывающий логику внутри абстрактного класса, и расширить его для каждого теста подкласса. Таким образом, вы можете убедиться, что эта логика будет проверяться для каждого ребенка отдельно.
источник