问题描述
为接口编写 junit 测试以便它们可用于具体实现类的最佳方法是什么?
What is the best way to write junit tests for interfaces so they can be used for the concrete implementing classes?
例如你有这个接口和实现类:
e.g. You have this interface and implementing classes:
public interface MyInterface {
/** Return the given value. */
public boolean myMethod(boolean retVal);
}
public class MyClass1 implements MyInterface {
public boolean myMethod(boolean retVal) {
return retVal;
}
}
public class MyClass2 implements MyInterface {
public boolean myMethod(boolean retVal) {
return retVal;
}
}
您将如何针对接口编写测试,以便将其用于类?
How would you write a test against the interface so you can use it for the class?
可能性 1:
public abstract class MyInterfaceTest {
public abstract MyInterface createInstance();
@Test
public final void testMyMethod_True() {
MyInterface instance = createInstance();
assertTrue(instance.myMethod(true));
}
@Test
public final void testMyMethod_False() {
MyInterface instance = createInstance();
assertFalse(instance.myMethod(false));
}
}
public class MyClass1Test extends MyInterfaceTest {
public MyInterface createInstance() {
return new MyClass1();
}
}
public class MyClass2Test extends MyInterfaceTest {
public MyInterface createInstance() {
return new MyClass2();
}
}
专业:
- 只需要实现一种方法
缺点:
- 所有测试的被测类的依赖项和模拟对象必须相同
可能性 2:
public abstract class MyInterfaceTest
public void testMyMethod_True(MyInterface instance) {
assertTrue(instance.myMethod(true));
}
public void testMyMethod_False(MyInterface instance) {
assertFalse(instance.myMethod(false));
}
}
public class MyClass1Test extends MyInterfaceTest {
@Test
public void testMyMethod_True() {
MyClass1 instance = new MyClass1();
super.testMyMethod_True(instance);
}
@Test
public void testMyMethod_False() {
MyClass1 instance = new MyClass1();
super.testMyMethod_False(instance);
}
}
public class MyClass2Test extends MyInterfaceTest {
@Test
public void testMyMethod_True() {
MyClass1 instance = new MyClass2();
super.testMyMethod_True(instance);
}
@Test
public void testMyMethod_False() {
MyClass1 instance = new MyClass2();
super.testMyMethod_False(instance);
}
}
专业:
- 每个测试的精细粒度,包括依赖项和模拟对象
缺点:
- 每个实现测试类都需要编写额外的测试方法
您更喜欢哪种可能性或您使用什么其他方式?
Which possibility would you prefer or what other way do you use?
推荐答案
与@dlev 给出的投票率高的答案相反,有时像您建议的那样编写测试非常有用/很有必要.类的公共 API,如通过其接口所表达的,是最重要的要测试的东西.话虽如此,我不会使用您提到的任何一种方法,而是使用 参数化 改为 test,其中参数是要测试的实现:
Contrary to the much-voted-up answer that @dlev gave, it can sometimes be very useful/needful to write a test like you're suggesting. The public API of a class, as expressed through its interface, is the most important thing to test. That being said, I would use neither of the approaches you mentioned, but a Parameterized test instead, where the parameters are the implementations to be tested:
@RunWith(Parameterized.class)
public class InterfaceTesting {
public MyInterface myInterface;
public InterfaceTesting(MyInterface myInterface) {
this.myInterface = myInterface;
}
@Test
public final void testMyMethod_True() {
assertTrue(myInterface.myMethod(true));
}
@Test
public final void testMyMethod_False() {
assertFalse(myInterface.myMethod(false));
}
@Parameterized.Parameters
public static Collection<Object[]> instancesToTest() {
return Arrays.asList(
new Object[]{new MyClass1()},
new Object[]{new MyClass2()}
);
}
}
这篇关于如何为接口编写junit测试?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!