JUnit5:在不重复代码的情况下测试多个类
JUnit5: Test multiple classes without repeating code
我在 Java 中构建了自己的堆栈实现,看起来像这样:
有提供基本功能(pop、push、peek 等)的接口"Stack"。然后我有 2 个具体的 classes,一个在数组的帮助下,一个在链表的帮助下(在这种情况下如何并不重要)。
现在我的问题是:我想用 JUnit5 测试这个,因为你不能实例化一个接口,我必须用数组测试每个函数一次 class 和 class 与链表,所以代码不必要地长。有没有一种方法可以测试接口或类似功能的所有功能?因为如果现在添加第三个实现,我将不得不重新全部重写。
我已经尝试了'ParameterizedTests',但我没有取得任何进展。
我很乐意提供帮助!
创建一个私有方法,在给定接口类型作为参数的情况下执行测试
private void testStack(Stack stack) {...}
然后在单元测试中调用它:
@Test
public void testImplementations() {
testStack(new ListStack());
testStack(new LinkedListStack());
}
我不知道 @ParameterizedTest
你面临什么问题,但正如你所要求的,这是一个非常通用的测试示例,可能对你的测试有用:
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
...
public static Stream<Arguments> provideStacks() {
return Stream.of(
Arguments.of(new ArrayStack()),
Arguments.of(new LinkedStack())
);
}
@ParameterizedTest
@MethodSource("provideStacks")
public void test(Stack stack) {
stack.push(1);
assertEquals(1, stack.pop());
}
public interface Stack {
void push(int i);
int pop();
}
public static final class ArrayStack implements Stack {
@Override
public void push(int i) {
}
@Override
public int pop() {
return 1;
}
}
public static final class LinkedStack implements Stack {
@Override
public void push(int i) {
}
@Override
public int pop() {
return 1;
}
}
Test Interfaces 是另一种可能性。您将测试定义为接口的默认方法,并在每个 Stack 实现中实现一次接口。每个实现都可以添加额外的测试等
interface StackContractTests {
Stack newEmptyStack();
@Test
default void popsWhatWasLastPushed() {
Stack stack = newEmptyStack();
stack.push("foo");
assertEquals("foo", stack.pop());
}
@Test
default void cannotPopFromEmptyStack() {
Stack stack = newEmptyStack();
assertThrows(EmptyStackException.class, stack::pop);
}
}
public class ArrayListBasedStackTests implements StackContractTests {
@Override
public Stack newEmptyStack() {
return new ArrayListBasedStack();
}
}
public class LinkedListBasedStackTests implements StackContractTests {
@Override
public Stack newEmptyStack() {
return new LinkedListBasedStack();
}
}
我在 Java 中构建了自己的堆栈实现,看起来像这样:
有提供基本功能(pop、push、peek 等)的接口"Stack"。然后我有 2 个具体的 classes,一个在数组的帮助下,一个在链表的帮助下(在这种情况下如何并不重要)。
现在我的问题是:我想用 JUnit5 测试这个,因为你不能实例化一个接口,我必须用数组测试每个函数一次 class 和 class 与链表,所以代码不必要地长。有没有一种方法可以测试接口或类似功能的所有功能?因为如果现在添加第三个实现,我将不得不重新全部重写。
我已经尝试了'ParameterizedTests',但我没有取得任何进展。
我很乐意提供帮助!
创建一个私有方法,在给定接口类型作为参数的情况下执行测试
private void testStack(Stack stack) {...}
然后在单元测试中调用它:
@Test
public void testImplementations() {
testStack(new ListStack());
testStack(new LinkedListStack());
}
我不知道 @ParameterizedTest
你面临什么问题,但正如你所要求的,这是一个非常通用的测试示例,可能对你的测试有用:
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
...
public static Stream<Arguments> provideStacks() {
return Stream.of(
Arguments.of(new ArrayStack()),
Arguments.of(new LinkedStack())
);
}
@ParameterizedTest
@MethodSource("provideStacks")
public void test(Stack stack) {
stack.push(1);
assertEquals(1, stack.pop());
}
public interface Stack {
void push(int i);
int pop();
}
public static final class ArrayStack implements Stack {
@Override
public void push(int i) {
}
@Override
public int pop() {
return 1;
}
}
public static final class LinkedStack implements Stack {
@Override
public void push(int i) {
}
@Override
public int pop() {
return 1;
}
}
Test Interfaces 是另一种可能性。您将测试定义为接口的默认方法,并在每个 Stack 实现中实现一次接口。每个实现都可以添加额外的测试等
interface StackContractTests {
Stack newEmptyStack();
@Test
default void popsWhatWasLastPushed() {
Stack stack = newEmptyStack();
stack.push("foo");
assertEquals("foo", stack.pop());
}
@Test
default void cannotPopFromEmptyStack() {
Stack stack = newEmptyStack();
assertThrows(EmptyStackException.class, stack::pop);
}
}
public class ArrayListBasedStackTests implements StackContractTests {
@Override
public Stack newEmptyStack() {
return new ArrayListBasedStack();
}
}
public class LinkedListBasedStackTests implements StackContractTests {
@Override
public Stack newEmptyStack() {
return new LinkedListBasedStack();
}
}