JUnit5: Test multiple classes without repeating code

狂风中的少年 提交于 2020-01-14 02:24:27

问题


I have built my own implementation of a stack in Java, which looks something like this:

There is the interface "Stack" which provides the basic functions (pop, push, peek etc.). And then I have 2 concrete classes, one with the help of arrays and the one with a linked list (how is not important in this case).

Now my question: I want to test this with JUnit5 and because you can't instantiate an interface, I have to test each function once for the class with the arrays and once for the class with the linked list, so the code is unnecessarily long. Is there a way that I can test all functions for the interface or something similar? Because if now a third implementation was added, I'd have to rewrite it all again.

I have already tried 'ParameterizedTests', but I have not made any progress.

I would be happy about help!


回答1:


I do not know what problem with @ParameterizedTest you are facing, but as you requested this is a very generic test example which could be useful for your test:

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



回答2:


Test Interfaces would be another possibility. You'd define your tests as default methods of an interface and implement the interface once per Stack implementation. Each implementation can add additional tests etc.

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



回答3:


Make a private method which performs the test given the interface type as a parameter

private void testStack(Stack stack) {...}

Then call it in a unit test:

@Test
public void testImplementations() {
     testStack(new ListStack());
     testStack(new LinkedListStack());
}


来源:https://stackoverflow.com/questions/47474695/junit5-test-multiple-classes-without-repeating-code

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!