![](/img/trans.png)
[英]How to make a method of an Abstract Class visible in Junit Test Cases in java?
[英]How to test abstract class in Java with JUnit?
我是使用 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 部分,我找到了这个链接,但我不明白作者想用这个例子说什么。 这行代码是什么意思?
public abstract Source getSource() ;
如果您没有该类的具体实现并且方法不是static
的,那么测试它们的意义何在? 如果您有一个具体类,那么您将测试这些方法作为具体类的公共 API 的一部分。
我知道你在想什么“我不想一遍又一遍地测试这些方法,这就是我创建抽象类的原因”,但我对此的反驳是单元测试的目的是允许开发人员进行更改,运行测试并分析结果。 这些更改的一部分可能包括覆盖抽象类的方法,包括protected
和public
,这可能会导致基本的行为变化。 根据这些更改的性质,它可能会以意想不到的、可能是负面的方式影响您的应用程序的运行方式。 如果您有一个好的单元测试套件,那么这些类型更改引起的问题在开发时应该很明显。
创建一个继承抽象类的具体类,然后测试具体类从抽象类继承的功能。
对于您发布的示例类,测试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;
}
...
ElectricCar
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
...
我会创建一个继承自抽象类的 jUnit 内部类。 这可以被实例化并且可以访问抽象类中定义的所有方法。
public class AbstractClassTest {
public void testMethod() {
...
}
}
class ConcreteClass extends AbstractClass {
}
你可以做这样的事情
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);
}
}
您可以实例化一个匿名类,然后测试该类。
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
抽象类ClassUnderTest
的属性myDependencyService
的可见性。
您还可以将此方法与 Mockito 巧妙地结合起来。 见这里。
我的测试方法非常简单,在每个abstractUnitTest.java
中。 我只是在 abstractUnitTest.java 中创建一个扩展抽象类的类。 并以这种方式进行测试。
作为一个选项,您可以创建覆盖抽象类内部逻辑的抽象测试类,并为每个子类测试扩展它。 这样您就可以确保为每个孩子单独测试此逻辑。
你不需要一个花哨的 Mockito 插件,或者匿名类,或者其他答案推荐的任何其他东西。 Junit 支持相互扩展的测试类:因此,为您的抽象基类编写一个彻底的抽象测试类(实际上只是使测试类抽象),它检查每个方法的行为方式。 对一组实例变量对象执行这些测试,这些对象是在此基础测试类的 @BeforeEach 方法中根据需要设置的。 让该方法调用一个抽象的 allocateObjects() 方法,该方法将完成所有对象分配。
然后,对于扩展您的抽象基础的每个类,都有一个扩展您刚刚编写的抽象测试类的测试类。 这个测试类将在被覆盖的 allocateObjects() 方法中进行实际的对象分配。 它分配的对象将由父测试类中的方法使用:由该测试类继承的方法,因此作为其测试的一部分运行。
你会做工厂傻事吗? 我猜:但是由于您可能无论如何都需要为每个子类创建测试类,所以您最好通过继承保持简单。 我想如果你有很多子类,并且它们都没有做任何值得从超类的东西测试的事情,那将是值得的:但是在那种情况下你到底为什么要创建子类呢?
不要在抽象类上进行@inject 模拟,而是创建一个间谍并在测试类本身中创建一个匿名实现,并使用它来测试你的抽象类。最好不要这样做,因为你可以做单元上不应该有任何公共方法test.Keep 它受保护并从已实现的类中调用这些方法并仅测试这些类。
你不能测试整个抽象类。 在这种情况下,您有抽象方法,这意味着它们应该由扩展给定抽象类的类来实现。
在那个类中,程序员必须编写专门用于他的逻辑的源代码。
换句话说,没有测试抽象类的意义,因为您无法检查它的最终行为。
如果您在某个抽象类中具有与抽象方法无关的主要功能,只需创建另一个抽象方法将引发异常的类。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.