如何使用JUnittestingJava中的抽象类?

我是使用JUnit进行Javatesting的新手。 我必须使用Java,我想使用unit testing。

我的问题是:我有一个抽象的类与一些抽象的方法。 但是有些方法不是抽象的。 我如何用JUnittesting这个类? 示例代码(非常简单):

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; } } 

我想testinggetSpeed()getFuel()函数。

对这个问题类似的问题在这里 ,但它不使用JUnit。

在JUnit FAQ部分,我find了这个链接 ,但我不明白作者想要用这个例子说什么。 这一行代码是什么意思?

 public abstract Source getSource() ; 

如果你没有具体的类的实现,而且方法不是static的,那testing它们的意义何在? 如果你有一个具体的类,那么你将testing这些方法作为具体类的公共API的一部分。

我知道你在想什么“我不想一遍又一遍地testing这些方法,这是我创build抽象类的原因”,但是我反驳的是,unit testing的重点是允许开发人员进行更改,运行testing,并分析结果。 其中一部分改变可能包括重写你的抽象类的方法,既可能是protected ,也可能是public ,这会导致基本的行为改变。 根据这些更改的性质,可能会影响应用程序以意想不到的方式运行,可能是负面的方式。 如果你有一个好的unit testing套件,这些types的变化引起的问题在开发时应该是明显的。

创build一个inheritance抽象类的具体类,然后testing具体类从抽象类inheritance的函数。

对于你发布的示例类,testinggetFuel()getSpeed()似乎没有什么意义,因为它们只能返回0(没有setter)。

然而,假设这只是一个简单的例子,为了说明的目的,并且你有合法的理由来testing抽象基类中的方法(其他人已经指出了这个含义),你可以设置你的testing代码,以便创build一个匿名为抽象方法提供虚拟(无操作)实现的基类的子类。

例如,在你的TestCase你可以这样做:

 c = new Car() { void drive() { }; }; 

然后testing其余的方法,例如:

 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,代码略有不同,但想法是一样的)。

如果你需要一个解决scheme(例如,因为你有太多的抽象类的实现,并且testing将总是重复相同的过程),那么你可以创build一个抽象testing类,抽象工厂方法将被执行testingclass。 这个例子适用于TestNG:

Car的抽象testing类:

 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; } ... 

unit testing类ElectricCarTestElectricCar

 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); } } 

使用嘲笑。 以Mockito为例。

我会创build一个inheritance自抽象类的jUnit子类。 这可以实例化,并可以访问抽象类中定义的所有方法。

你不能testing整个抽象类。 在这种情况下,你有抽象的方法,这意味着它们应该由扩展给定抽象类的类来实现。

在那个类中,程序员必须编写专用于他的逻辑的源代码。

换句话说,没有testing抽象类的感觉,因为你无法检查它的最终行为。

如果您在某些抽象类中具有与抽象方法无关的主要function,只需创build另一个抽象方法会抛出一些exception的类即可。

你可以实例化一个匿名类,然后testing这个类。

 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); } } 

请记住,必须为抽象类ClassUnderTest的属性myDependencyService protected可见性。

你也可以把这个方法整齐地与Mockito结合起来。 看到这里 。