How to test abstract class in Java with JUnit?
对于JUnit的Java测试,我是新手。我必须使用Java,我想使用单元测试。
我的问题是:我有一个带有一些抽象方法的抽象类。但有些方法并不抽象。我如何用JUnit测试这门课?示例代码(非常简单):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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; } } |
我想测试
与这个问题类似的问题在这里,但它没有使用JUnit。
在JUnitFAQ部分,我找到了这个链接,但是我不理解作者想用这个例子说什么。这行代码是什么意思?
1 | public abstract Source getSource() ; |
如果您没有类的具体实现,并且方法不是
我知道你在想什么,"我不想反复测试这些方法,这就是我创建抽象类的原因",但我的反驳是,单元测试的重点是允许开发人员进行更改、运行测试和分析结果。这些更改的一部分可能包括重写抽象类的方法,包括
创建一个继承抽象类的具体类,然后测试具体类从抽象类继承的函数。
对于您发布的示例类,测试
但是,假设这只是一个用于说明目的的简化示例,并且您有正当理由在抽象基类中测试方法(其他人已经指出了其含义),您可以设置测试代码,以便它创建一个只提供虚拟(不提供op)实现的基类的匿名子类。抽象方法。
例如,在您的
1 2 3 | c = new Car() { void drive() { }; }; |
然后测试其他方法,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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:
1 2 3 4 5 6 7 8 9 10 11 | 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); ... |
执行
1 2 3 4 5 6 7 8 9 10 | class ElectricCar extends Car { private final int batteryCapacity; public ElectricCar(int speed, int fuel, int batteryCapacity) { super(speed, fuel); this.batteryCapacity = batteryCapacity; } ... |
1 2 3 4 5 6 7 8 9 | 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 ... |
你可以这样做
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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内部类。这可以被实例化,并且可以访问抽象类中定义的所有方法。
1 2 3 4 5 6 7 8 9 10 | public class AbstractClassTest { public void testMethod() { ... } } class ConcreteClass extends AbstractClass { } |
您可以实例化一个匿名类,然后测试该类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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); } } |
记住,对于抽象类
您还可以将此方法与Mockito巧妙地结合起来。请看这里。
我的测试方法非常简单,在每个
作为一个选项,您可以在抽象类内创建覆盖逻辑的抽象测试类,并为每个子类测试扩展它。这样,您就可以确保对每个孩子分别测试这个逻辑。
不能测试整个抽象类。在本例中,您有抽象方法,这意味着它们应该由扩展给定抽象类的类实现。
在这个类中,程序员必须编写专用于他的逻辑的源代码。
换句话说,没有测试抽象类的感觉,因为您无法检查抽象类的最终行为。
如果您有与某些抽象类中的抽象方法无关的主要功能,只需创建另一个类,抽象方法将在其中引发一些异常。