有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我不熟悉使用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

在JUnitFAQ部分,我找到了this link,但我不明白作者想用这个例子说什么。这行代码是什么意思

public abstract Source getSource() ;

共 (6) 个答案

  1. # 1 楼答案

    如果您仍然需要解决方案(例如,因为抽象类的实现太多,测试总是重复相同的过程),那么您可以使用抽象工厂方法创建一个抽象测试类,该方法将由该测试类的实现执行。以下示例适用于TestNG:

    的抽象测试类:

    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

    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
        ...
    
  2. # 2 楼答案

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

    public class AbstractClassTest {
       public void testMethod() {
       ...
       }
    }
    
    
    class ConcreteClass extends AbstractClass {
    
    }
    
  3. # 3 楼答案

    对于您发布的示例类,测试getFuel()getSpeed()似乎没有多大意义,因为它们只能返回0(没有setter)

    然而,假设这只是一个简单的示例,用于说明目的,并且您有正当的理由在抽象基类中测试方法(其他人已经指出了其含义),您可以设置测试代码,以便它创建一个基类的匿名子类,只为抽象方法提供虚拟(无操作)实现

    例如,在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,代码可能略有不同,但想法相同。)

  4. # 4 楼答案

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

  5. # 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);
        }
    }
    
  6. # 6 楼答案

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

    我知道你在想什么“我不想反复测试这些方法,这就是我创建抽象类的原因”,但我的反对意见是,单元测试的目的是允许开发人员进行更改、运行测试和分析结果。这些更改的一部分可能包括重写抽象类的protectedpublic方法,这可能会导致基本的行为更改。根据这些更改的性质,它可能会以意外的、可能是负面的方式影响应用程序的运行。如果你有一个很好的单元测试套件,那么在开发的时候,这些类型的变化会引起明显的问题