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();
    }
}