我想知道如何单元测试抽象类,以及扩展抽象类的类。
我是否应该通过扩展抽象类来测试它,去掉抽象方法,然后测试所有的具体方法?然后只测试我重写的方法,并在单元测试中测试扩展抽象类的对象的抽象方法?
我是否应该有一个抽象测试用例,可以用来测试抽象类的方法,并在测试用例中为扩展抽象类的对象扩展该类?
注意,我的抽象类有一些具体的方法。
我想知道如何单元测试抽象类,以及扩展抽象类的类。
我是否应该通过扩展抽象类来测试它,去掉抽象方法,然后测试所有的具体方法?然后只测试我重写的方法,并在单元测试中测试扩展抽象类的对象的抽象方法?
我是否应该有一个抽象测试用例,可以用来测试抽象类的方法,并在测试用例中为扩展抽象类的对象扩展该类?
注意,我的抽象类有一些具体的方法。
当前回答
如果具体方法调用任何抽象方法,该策略将不起作用,您将希望分别测试每个子类的行为。否则,只要抽象类的具体方法与子类解耦,就可以像您所描述的那样扩展它并存根抽象方法。
其他回答
首先,如果抽象类包含一些具体的方法,我认为你应该这样做,考虑这个例子
public abstract class A
{
public boolean method 1
{
// concrete method which we have to test.
}
}
class B extends class A
{
@override
public boolean method 1
{
// override same method as above.
}
}
class Test_A
{
private static B b; // reference object of the class B
@Before
public void init()
{
b = new B ();
}
@Test
public void Test_method 1
{
b.method 1; // use some assertion statements.
}
}
遵循@patrick-desjardins的回答,我实现了抽象和它的实现类@Test,如下所示:
抽象类- ABC.java
import java.util.ArrayList;
import java.util.List;
public abstract class ABC {
abstract String sayHello();
public List<String> getList() {
final List<String> defaultList = new ArrayList<>();
defaultList.add("abstract class");
return defaultList;
}
}
由于抽象类不能被实例化,但它们可以被子类化,具体类DEF.java如下:
public class DEF extends ABC {
@Override
public String sayHello() {
return "Hello!";
}
}
测试类来测试抽象方法和非抽象方法:
import org.junit.Before;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.contains;
import java.util.Collection;
import java.util.List;
import static org.hamcrest.Matchers.equalTo;
import org.junit.Test;
public class DEFTest {
private DEF def;
@Before
public void setup() {
def = new DEF();
}
@Test
public void add(){
String result = def.sayHello();
assertThat(result, is(equalTo("Hello!")));
}
@Test
public void getList(){
List<String> result = def.getList();
assertThat((Collection<String>) result, is(not(empty())));
assertThat(result, contains("abstract class"));
}
}
使用抽象类的主要动机之一是在应用程序中启用多态性——即:您可以在运行时替换不同的版本。事实上,这与使用接口非常相似,只是抽象类提供了一些常见的管道,通常称为模板模式。
从单元测试的角度来看,有两件事需要考虑:
抽象类与相关类的交互。对于这种情况,使用模拟测试框架是理想的,因为它表明您的抽象类可以很好地与其他类协作。 派生类的功能。如果您为派生类编写了自定义逻辑,则应该单独测试这些类。
编辑:RhinoMocks是一个很棒的模拟测试框架,它可以通过动态地从您的类派生在运行时生成模拟对象。这种方法可以为您节省大量手工编写派生类的时间。
编写一个Mock对象,并仅用于测试。它们通常是非常非常小的(继承自抽象类),而不是更多。然后,在你的单元测试中,你可以调用你想测试的抽象方法。
您应该测试包含一些逻辑的抽象类,就像您拥有的所有其他类一样。
这是我在设置一个测试抽象类的工具时通常遵循的模式:
public abstract class MyBase{
/*...*/
public abstract void VoidMethod(object param1);
public abstract object MethodWithReturn(object param1);
/*,,,*/
}
以及我在测试中使用的版本:
public class MyBaseHarness : MyBase{
/*...*/
public Action<object> VoidMethodFunction;
public override void VoidMethod(object param1){
VoidMethodFunction(param1);
}
public Func<object, object> MethodWithReturnFunction;
public override object MethodWithReturn(object param1){
return MethodWihtReturnFunction(param1);
}
/*,,,*/
}
如果在我不期望它的时候调用抽象方法,测试就会失败。在安排测试时,我可以很容易地用lambdas剔除抽象方法,这些方法执行断言、抛出异常、返回不同的值等。