如何使用JUnit在Java中测试抽象类?

时间:2011-09-27 12:53:24

标签: java junit abstract-class

我是JUnit的Java测试新手。我必须使用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()函数。

此问题的类似问题是here,但它没有使用JUnit。

在JUnit FAQ部分,我找到了this link,但我不明白作者想用这个例子说些什么。这行代码意味着什么?

public abstract Source getSource() ;

10 个答案:

答案 0 :(得分:102)

如果你没有具体的类实现,并且方法不是static那么测试它们的重点是什么?如果你有一个具体的类,那么你将测试这些方法作为具体类的公共API的一部分。

我知道你在想什么“我不想一遍又一遍地测试这些方法,这就是我创建抽象类的原因”,但我的反驳论点是单元测试的重点是让开发人员能够进行更改,运行测试并分析结果。这些变化的一部分可能包括覆盖抽象类的方法,protectedpublic,这可能导致基本的行为变化。根据这些更改的性质,它可能会影响您的应用程序以意外的方式运行,可能是负面的方式。如果你有一个好的单元测试套件,这些类型引起的问题在开发时应该是明显的。

答案 1 :(得分:30)

创建一个继承抽象类的具体类,然后测试具体类从抽象类继承的函数。

答案 2 :(得分:12)

使用您发布的示例类,测试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,代码会略有不同,但想法是一样的。)

答案 3 :(得分:8)

如果你还需要一个解决方案(例如,因为你有太多的抽象类实现,并且测试总是会重复相同的过程),那么你可以用一个抽象的工厂方法创建一个抽象的测试类,该方法将由该测试类的实现。这个例子可以和我一起使用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
    ...

答案 4 :(得分:5)

你可以做这样的事情

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

答案 5 :(得分:3)

我将创建一个继承自抽象类的jUnit内部类。这可以实例化,并且可以访问抽象类中定义的所有方法。

public class AbstractClassTest {
   public void testMethod() {
   ...
   }
}


class ConcreteClass extends AbstractClass {

}

答案 6 :(得分:2)

您可以实例化一个匿名类,然后测试该类。

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巧妙地结合起来。请参阅here

答案 7 :(得分:1)

在每个abstractUnitTest.java中,我的测试方法非常简单。我只是在abstractUnitTest.java中创建了一个扩展抽象类的类。然后以这种方式进行测试。

答案 8 :(得分:0)

您无法测试整个抽象类。在这种情况下,您有抽象方法,这意味着它们应该由扩展给定抽象类的类实现。

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

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

如果您在某些抽象类中具有与抽象方法无关的主要功能,则只需创建另一个抽象方法将引发异常的类。

答案 9 :(得分:0)

作为一个选项,您可以创建抽象测试类,覆盖抽象类中的逻辑,并为每个子类测试扩展它。因此,通过这种方式,您可以确保为每个孩子单独测试此逻辑。