在一个参数化类(junit)中创建多个参数集

Jer*_*vel 48 java junit parameterized parameterized-unit-test

目前,我必须为每个我想用几个不同输入测试的方法创建一个参数化测试类.有没有办法在一个文件中添加它?

现在有CalculatorTestAdd.java一组参数用于检查Add()功能是否正常工作.我是否有可能将此连接"连接"到该Add()函数并为该Subtract()方法创建一个额外的集合并在同一测试类中添加此方法,从而导致一个文件被调用CalculatorTest.java

nes*_*.gp 54

这个答案类似于Tarek的一个(参数化部分),尽管我认为它更具有可扩展性.也可以解决您的问题,如果一切正确,您将不会失败测试:

@RunWith(Parameterized.class)
public class CalculatorTest {
    enum Type {SUBSTRACT, ADD};
    @Parameters
    public static Collection<Object[]> data(){
        return Arrays.asList(new Object[][] {
          {Type.SUBSTRACT, 3.0, 2.0, 1.0},
          {Type.ADD, 23.0, 5.0, 28.0}
        });
    }

    private Type type;
    private Double a, b, expected;

    public CalculatorTest(Type type, Double a, Double b, Double expected){
        this.type = type;
        this.a=a; this.b=b; this.expected=expected;
    }

    @Test
    public void testAdd(){
        Assume.assumeTrue(type == Type.ADD);
        assertEquals(expected, Calculator.add(a, b));
    }

    @Test
    public void testSubstract(){
        Assume.assumeTrue(type == Type.SUBSTRACT);
        assertEquals(expected, Calculator.substract(a, b));
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 一个优雅的解决方法。这就像在说“这个测试方法只适用于这个数据集”。这允许灵活地拥有例如使用数据集 1 的 2 种测试方法和使用数据集 2 的 3 种测试方法。 (2认同)
  • 不错的解决方案 - 但是如果每个测试用例需要不同的构造函数会发生什么? (2认同)

Ale*_*lex 14

在我看来,另一个纯JUnit但又优雅的解决方案是将每个参数化测试封装在它们自己的内部静态类中,并在顶级测试类中使用Enclosed test runner.这样,您不仅可以为每个测试彼此独立地使用不同的参数值,还可以使用完全不同的参数测试方法.

这是它的样子:

@RunWith(Enclosed.class)
public class CalculatorTest {

  @RunWith(Parameterized.class)
  public static class AddTest {

    @Parameters
    public static Collection<Object[]> data() {
      return Arrays.asList(new Object[][] {
          { 23.0, 5.0, 28.0 }
      });
    }

    private Double a, b, expected;

    public AddTest(Double a, Double b, Double expected) {
      this.a = a;
      this.b = b;
      this.expected = expected;
    }

    @Test
    public void testAdd() {
      assertEquals(expected, Calculator.add(a, b));
    }
  }

  @RunWith(Parameterized.class)
  public static class SubstractTest {

    @Parameters
    public static Collection<Object[]> data() {
      return Arrays.asList(new Object[][] {
          { 3.0, 2.0, 1.0 }
      });
    }

    @Parameter(0)
    private Double a;
    @Parameter(1)
    private Double b;
    @Parameter(2)
    private Double expected;

    @Test
    public void testSubstract() {
      assertEquals(expected, Calculator.substract(a, b));
    }
  }

  @RunWith(Parameterized.class)
  public static class MethodWithOtherParametersTest {

    @Parameters
    public static Collection<Object[]> data() {
      return Arrays.asList(new Object[][] {
          { 3.0, 2.0, "OTHER", 1.0 }
      });
    }

    private Double a;
    private BigDecimal b;
    private String other;
    private Double expected;

    public MethodWithOtherParametersTest(Double a, BigDecimal b, String other, Double expected) {
      this.a = a;
      this.b = b;
      this.other = other;
      this.expected = expected;
    }

    @Test
    public void testMethodWithOtherParametersTest() {
      assertEquals(expected, Calculator.methodWithOtherParametersTest(a, b, other));
    }
  }

  public static class OtherNonParameterizedTests {

    // here you can add any other test which is not parameterized

    @Test
    public void otherTest() {
      // test something else
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

注意的使用@Parameter注释的SubstractTest,我认为更具有可读性.但这更多的是品味问题.


Tar*_*rek 13

我相信你不再有这个问题了,但我想到了你可以做到的3种方法,每种方式都有其优点和缺点.使用参数化跑步者,您将不得不使用变通方法.

- 使用参数化的更多参数

如果必须在外部加载参数,只需为预期结果添加参数即可.

优点:减少编码,并运行所有测试.

缺点:每组不同测试的新参数.

@RunWith(Parameterized.class)
public class CalculatorTest extends TestCase {
    private Calculator calculator;
    private int operator1;
    private int operator2;
    private int expectedSum;
    private int expectedSub;

    public CalculatorTest(int operator1, int operator2, int expectedSum, int expectedSub) {
        this.operator1 = operator1;
        this.operator2 = operator2;
    }

    @Params
    public static Collection<Object[]> setParameters() {
        Collection<Object[]> params = new ArrayList<>();
        // load the external params here
        // this is an example
        params.add(new Object[] {2, 1, 3, 1});
        params.add(new Object[] {5, 2, 7, 3});

        return params;
    }

    @Before
    public void createCalculator() {
        calculator = new Calculator();
    }

    @Test
    public void addShouldAddTwoNumbers() {
        assertEquals(expectedSum, calculator.add(operator1, operator2));
    }

    @Test
    public void subtractShouldSubtractTwoNumbers() {
        assertEquals(expectedSub, calculator.subtract(operator1, operator2));
    }

    @After
    public void endTest() {
        calculator = null;
        operator1 = null;
        operator2 = null;
        expectedSum = null;
        expectedSub = null;
    }
}
Run Code Online (Sandbox Code Playgroud)

- 不使用参数化跑步者

如果以编程方式设置参数,这可以正常工作.

优点:您可以根据需要进行尽可能多的测试,而无需设置大量参数.

缺点:更多编码,它在第一次失败时停止(可能不是骗局).

@RunWith(JUnit4.class)
public class CalculatorTest extends TestCase {
    private Calculator calculator;

    @Before
    public void createCalculator() {
        calculator = new Calculator();
    }

    @Test
    public void addShouldAddTwoNumbers() {
        int[] operator1 = {1, 3, 5};
        int[] operator2 = {2, 7, 9};
        int[] expectedResults = {3, 10, 14};

        for (int i = 0; i < operator1.length; i++) {
            int actualResult = calculator.add(operator1[i], operator2[i]);
            assertEquals(expectedResults[i], actualResult);
        }
    }

    @Test
    public void subtractShouldSubtractTwoNumbers() {
        int[] operator1 = {5, 8, 7};
        int[] operator2 = {1, 2, 10};
        int[] expectedResults = {4, 6, -3};

        for (int i = 0; i < operator1.length; i++) {
            int actualResult = calculator.subtract(operator1[i], operator2[i]);
            assertEquals(expectedResults[i], actualResult);
        }
    }

    @After
    public void endTest() {
        calculator = null;
    }
}
Run Code Online (Sandbox Code Playgroud)

- 使用JUnitParams

我与实用主义者没有任何关系,我几天前就发现了这一点.该框架在JUnit之上运行,并以不同方式处理参数化测试.参数直接传递给测试方法,因此您可以在同一个类中为不同的方法使用不同的参数.

优点:实现与上述解决方案相同的结果,无需解决方法.

缺点:也许您的公司不允许您向项目添加新的依赖项或强制您使用某些奇怪的编码规则(例如仅使用参数化运行程序).让我们面对它,它发生的比我们想要的更多.

是一个很好的JUnitParams实例,你可以在这个Github页面上获得项目/检查代码.


pio*_*rek 11

你可以使用https://github.com/piotrturski/zohhak的参数:

@TestWith({
   "1, 7, 8",
   "2, 9, 11"
})
public void addTest(int number1, int number2, int expectedResult) {
    BigDecimal result = calculator.add(number1, number2);
    assertThat(result).isEqualTo...
}
Run Code Online (Sandbox Code Playgroud)

如果您要从文件加载参数,可以使用http://code.google.com/p/fuzztester/http://code.google.com/p/junitparams/

如果你需要真正的灵活性,你可以使用junit的@Parameterized,但它会使你的代码变得混乱.你也可以使用junit的理论 - 但它似乎对计算器测试来说太过分了


Boh*_*ian 8

是.你不需要做什么特别的事.对于参数的每组值,每个@Test方法运行一次,因此只需要一个方法测试add()和另一个方法测试subtract().

我还要补充一点,指明这一要求的人是误入歧途的.在"适用于所有情况"中规定某些设计模式几乎没有价值 - 不妨聘请训练有素的猴子.


Ank*_*dia 5

好了,现在,JUnit-5为您提供了一个解决方案-通过重新定义编写参数化测试的方式。现在,可以使用@ParameterizedTest在方法级别定义参数化测试,并可以使用@MethodSource为其提供方法源

因此,在您的情况下,您可以有2个单独的数据源方法来为add()和减去()测试方法提供输入数据,这两个方法都在同一类中。您的代码应如下所示:

public class CalculatorTest{
    public static int[][] dataSetForAdd() {
        return new int[][] { { 1 , 2, 3 }, { 2, 4, 6 }, { 121, 4, 125 } };
    }

    public static int[][] dataSetForSubtract() {
        return new int[][] { { 1 , 2, -1 }, { 2, 4, -2 }, { 121, 4, 117 } };
    }

    @ParameterizedTest
    @MethodSource(names = "dataSetForAdd")
    void testCalculatorAddMethod(int[] dataSetForAdd) {
        Calculator calculator= new Calculator();
        int m1 = dataSetForAdd[0];
        int m2 = dataSetForAdd[1];
        int expected = dataSetForAdd[2];
        assertEquals(expected, calculator.add(m1, m2));
    }

    @ParameterizedTest
    @MethodSource(names = "dataSetForSubtract")
    void testCalculatorAddMethod(int[] dataSetForSubtract) {
        Calculator calculator= new Calculator();
        int m1 = dataSetForSubtract[0];
        int m2 = dataSetForSubtract[1];
        int expected = dataSetForSubtract[2];
        assertEquals(expected, calculator.subtract(m1, m2));
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

使用 Junit Jupiter:https : //www.petrikainulainen.net/programming/testing/junit-5-tutorial-writing-parameterized-tests/

import intf.ICalculator;

public class Calculator implements ICalculator {
    @Override
    public int plus(int a, int b) {return a + b; }

    @Override
    public int minuis(int a, int b) {return a - b;}

    @Override
    public int multy(int a, int b) {return a * b;}

    @Override  // check in junit byZero
    public int divide(int a, int b) {return a / b;}

}
Run Code Online (Sandbox Code Playgroud)

测试类:

import static org.junit.Assert.assertEquals;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

class CalculatorJupiter5Test {

    Calculator calculator = new Calculator();

    @DisplayName("Should calculate the correct sum")
    @ParameterizedTest(name = "{index} => a={0}, b={1}, sum={2}")
    @CsvSource({
            "5, 3, 8",
            "1, 3, 4",
            "6, 6, 12",
            "2, 3, 5"
    })
    void sum(int a, int b, int sum) {
        assertEquals(sum, calculator.plus(a, b) );
    }

    @DisplayName("Should calculate the correct multy")
    @ParameterizedTest(name = "{index} => a={0}, b={1}, multy={2}")
    @CsvSource({
        "5, 3, 15",
        "1, 3, 3",
        "6, 6, 36",
        "2, 3, 6"
    })
    void multy(int a, int b, int multy) {
        assertEquals(multy, calculator.multy(a, b) );
    }

    @DisplayName("Should calculate the correct divide")
    @ParameterizedTest(name = "{index} => a={0}, b={1}, divide={2}")
    @CsvSource({
        "5, 3, 1",
        "14, 3, 4",
        "6, 6, 1",
        "36, 2,  18"
    })
    void divide(int a, int b, int divide) {
        assertEquals(divide, calculator.divide(a, b) );
    }

   @DisplayName("Should calculate the correct divide by zero")
   @ParameterizedTest(name = "{index} => a={0}, b={1}, divide={2}")
   @CsvSource({
      "5, 0, 0",
   })
    void divideByZero(int a, int b, int divide) {
     assertThrows(ArithmeticException.class,
         () -> calculator.divide(a , b),
         () -> "divide by zero");
    }

    @DisplayName("Should calculate the correct minuis")
    @ParameterizedTest(name = "{index} => a={0}, b={1}, minuis={2}")
    @CsvSource({
        "5, 3, 2",
        "1, 3, -2",
        "6, 6, 0",
        "2, 3, -1"
    })
    void minuis(int a, int b, int minuis) {
        assertEquals(minuis, calculator.minuis(a, b) );
    }
}
Run Code Online (Sandbox Code Playgroud)