对B 和C 使用相同的测试意味着,您实际上是通过接口A 进行测试。这些将主要是黑盒测试,因为您的测试只能依赖于接口的元素,而不是B 和C 中特定实现的元素。更多信息请参见下文。
然而,首先,一些示例代码如何实现您的目标:该方法使用使用 @MethodSource 的 Junit 5 参数化测试。在示例中,@MethodSource 提供了作为参数 a) 测试的描述(在测试方法逻辑中未使用,因此在此处称为 dummy),b) 实现接口 @ 的类之一的实例987654329@,并且,作为一个工作示例,您可以试验一下,c) 对象的预期类名。
接口A代码:
package so56386880;
public interface A {
public void color();
}
B 类和 C 类的代码(我使用相同的代码,此处显示 B):
package so56386880;
public class B implements A {
public void color() { }
}
测试代码
package so56386880;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
class A_Test {
@DisplayName("Test one common property of color method")
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("provideImplementors")
void color_whenCalled_shallXxx(String dummy, A someA, String expectedClassName) {
// you would do some test for someA.color(), but just for example:
assertEquals(expectedClassName, someA.getClass().getName());
}
static Stream<Arguments> provideImplementors() {
return Stream.of(
Arguments.of("expecting class B's name", new B(), "so56386880.B"),
Arguments.of("expecting class C's name", new C(), "so56386880.C"));
}
}
如上所述,这只能执行仅限于使用接口A 的测试。由于B 和C 将有不同的实现,您可能还需要对B 和C 进行一些特定的测试。请记住,测试的目标是发现错误 - 不同的实现通常具有不同的潜在错误(不同的控制流、不同的溢出可能性等)。
更新:上面的解决方案回答了如何使用将被测类作为参数提供的参数化测试来做到这一点。另一种方法是为接口as below 实现一个测试类:
package so56386880;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
abstract class A_Test2 {
public abstract A getClassUnderTest();
@Test
void color_whenCalled_shallXxx() {
A classUnderTest = this.getClassUnderTest();
classUnderTest.color(); // exercise
assertEquals(expected..., actual...);
}
}
然后从中派生出来,如下图:
package so56386880;
class B_Test extends A_Test2 {
public A getClassUnderTest() { return new B(); }
}
当在 Junit 5 下运行 B_Test 时,基类中的所有测试方法都会被执行(如果在 B_Test 中定义,还会执行其他测试方法)。优点是,无论何时创建新的派生类,您都不必修改 A_Test2。但是,如果每个派生类的预期值不同(就像第一个解决方案中的类名一样),则需要进行一些调整,例如更多类似于 getClassUnderTest 的回调方法。