Xen*_*pus 69 java testing junit unit-testing interface
为接口编写junit测试的最佳方法是什么,以便它们可用于具体的实现类?
例如,你有这个接口和实现类:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
您如何针对界面编写测试,以便将其用于课程?
可能性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();
}
}
Run Code Online (Sandbox Code Playgroud)
优点:
缺点:
可能性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);
}
}
Run Code Online (Sandbox Code Playgroud)
优点:
缺点:
您更喜欢哪种可能性或使用其他方式?
Rya*_*art 73
与@dlev给出的高得多的答案相反,编写像你建议的测试有时非常有用/需要.通过其接口表示的类的公共API是最重要的测试.话虽这么说,我不会使用你提到的方法,而是使用参数化测试,其中参数是要测试的实现:
@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()}
);
}
}
Run Code Online (Sandbox Code Playgroud)
Ced*_*ust 14
我也不同意dlev,对接口而不是具体实现编写测试没有任何问题.
您可能想要使用参数化测试.以下是使用TestNG的样子,使用JUnit更加节省(因为你不能直接将参数传递给测试函数):
@DataProvider
public Object[][] dp() {
return new Object[][] {
new Object[] { new MyImpl1() },
new Object[] { new MyImpl2() },
}
}
@Test(dataProvider = "dp")
public void f(MyInterface itf) {
// will be called, with a different implementation each time
}
Run Code Online (Sandbox Code Playgroud)
jwa*_*ins 10
该主题的后期添加,分享更新的解决方案见解
我也在寻找一种适当而有效的测试方法(基于JUnit)一些接口和抽象类的多个实现的正确性.不幸的是,JUnit的@Parameterized
测试,也不TestNG的等价概念正确符合我的要求,因为我不知道先验的存在可能这些接口/抽象类的实现的列表.也就是说,可能会开发新的实现,测试人员可能无法访问所有现有的实现; 因此,让测试类指定实现类列表是没有效率的.
在这一点上,我发现以下项目似乎提供了一个完整而有效的解决方案来简化这种类型的测试:https://github.com/Claudenw/junit-contracts.它基本上允许通过@Contract(InterfaceClass.class)
合同测试类的注释来定义"合同测试" .然后,实现者将创建一个特定于实现的测试类,带有注释@RunWith(ContractSuite.class)
和@ContractImpl(value = ImplementationClass.class)
; 引擎应自动应用任何适用于ImplementationClass的合同测试,方法是查找为ImplementationClass派生的任何接口或抽象类定义的所有合同测试.我还没有测试过这个解决方案,但这听起来很有希望.
我还找到了以下库:http://www.jqno.nl/equalsverifier/.这个满足了类似但更具体的需求,它特别声明了Object.equals和Object.hashcode契约的类一致性.
同样,https: //bitbucket.org/chas678/testhelpers/src演示了验证一些Java fondamental合同的策略,包括Object.equals,Object.hashcode,Comparable.compare,Serializable.这个项目使用简单的测试结构,我相信,它可以很容易地被复制以满足任何特定需求.
那就是现在呢; 我将使用我可能找到的其他有用信息更新此帖子.
我通常会避免针对接口编写单元测试,原因很简单,接口,无论你想要多少,都没有定义功能.它使用语法要求阻碍了它的实现者,但就是这样.
相反,单元测试旨在确保您期望的功能存在于给定的代码路径中.
话虽这么说,但有些情况下这种类型的测试才有意义.假设您希望这些测试确保您编写的类(共享给定接口)实际上共享相同的功能,那么我更希望您的第一个选项.它使实现子类最容易将自己注入到测试过程中.另外,我不认为你的"骗局"是真的.没有理由你不能让真正受测试的类提供他们自己的模拟(虽然我认为如果你真的需要不同的模拟,那么这表明你的接口测试无论如何都不统一.)