web-dev-qa-db-ja.com

1つのパラメーター化されたクラス(junit)に複数のパラメーターセットを作成する

現在、いくつかの異なる入力でテストするすべてのメソッドに対して、パラメーター化されたテストクラスを作成する必要があります。これを1つのファイルに一緒に追加する方法はありますか?

現在、Add()関数が適切に動作するかどうかを確認するために使用されるパラメーターのセットを持っている_CalculatorTestAdd.Java_があります。このセットをAdd()関数に「接続」し、Subtract()メソッド用の追加セットを作成し、同じテストクラスにこのメソッドを追加する可能性はありますか? _CalculatorTest.Java_?という1つのファイル

46
Jeroen Vannevel

はい。あなたがしなければならない特別なことは何もありません。パラメーターの値のセットごとに、各@Testメソッドが1回実行されるため、1つのメソッドがadd()をテストし、別のメソッドが減算()をテストするだけです。

また、この要件を口述している人物が誤った方向に導かれていることを付け加えてください。特定のデザインパターンを「すべての場合」に指示することにはほとんど価値がありません。訓練を受けたサルを雇うこともできます。

8
Bohemian

この答えは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));
    }
}
52
nessa.gp

この問題はもう発生していないと思いますが、長所と短所のある3つの方法を考えました。パラメータ化されたランナーでは、回避策を使用する必要があります。

-Parameterizedでより多くのパラメーターを使用する

パラメーターを外部からロードする必要がある場合は、予想される結果のパラメーターを追加するだけです。

長所:コーディングが少なく、すべてのテストを実行します。

短所:テストの異なるセットごとに新しいパラメーター。

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

-パラメーター化されたランナーを使用しない

パラメータをプログラムで設定する場合、これは正常に機能します。

長所:膨大なパラメーターを設定しなくても、必要なだけテストを実行できます。

Cons:より多くのコーディングを行い、最初の失敗で停​​止します(これはconではない可能性があります)。

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

-JUnitParamsの使用

私はプラグマティストと提携していません。数日前に見つけました。このフレームワークはJUnitの上で実行され、パラメーター化されたテストを異なる方法で処理します。パラメーターはテストメソッドに直接渡されるため、同じクラスでメソッドごとに異なるパラメーターを使用できます。

長所:回避策なしで上記のソリューションと同じ結果を達成します。

短所:多分あなたの会社はあなたがプロジェクトに新しい依存関係を追加することを許可していないか、いくつかの奇妙なコーディングルールを使用することを強制しています(パラメータ化されたランナーを使用するなど)排他的に)。それに直面しましょう、それは私たちが望んでいる以上に起こります。

ここ は、動作中のJUnitParamsの良い例です。プロジェクトを取得したり、このコードを確認したりできます Github ページ。

13
Tarek

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

ファイルからパラメータをロードする場合は、 http://code.google.com/p/fuzztester/ または http://code.google.com/p/を使用できます。 junitparams /

実際の柔軟性が必要な場合は、junitの@Parameterizedを使用できますが、コードが乱雑になります。あなたもjunitの理論を使用することができます-しかし、それは電卓テストのためにやり過ぎだと思われます

10
piotrek

別の純粋なJUnitですが、私の考えではエレガントなソリューションは、各パラメーター化されたテストを独自の内部静的クラスにカプセル化し、トップレベルのテストクラスで Enclosed テストランナーを使用することです。これにより、テストごとに異なるパラメーター値を互いに独立して使用できるだけでなく、まったく異なるパラメーターを使用してメソッドをテストすることもできます。

これは次のようになります。

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

SubstractTest@Parameterアノテーションの使用に注意してください。これは読みやすいと思います。しかし、これは好みの問題です。

10
Alex

さて、今、JUnit-5はこのためのソリューションを提供します-パラメーター化されたテストを書く方法を再定義することによって。パラメータ化されたテストは、@ ParameterizedTestを使用してメソッドレベルで定義でき、@ MethodSource。を使用してメソッドソースを指定できます。

したがって、あなたの場合、add()とsubtract()テストメソッドの入力データを提供する2つの別々のデータソースメソッドを両方とも同じクラスに持つことができます。コードは次のようになります。

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));
    }
}
5
Ankit Singodia

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

}

テストクラス:

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) );
    }
}
2
Fox user9219598

junitparamsを使用します。これにより、各テストで個別のパラメーターセットを渡すことができます。 JunitParamsはメソッドを使用してparamsのセットを返します。テストでは、メソッド名をparam入力のソースとして提供するため、メソッド名を変更するとデータセットが変更されます。

import com.xx.xx.xx.Transaction;
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import Java.util.Arrays;
import Java.util.List;
import Java.util.Set;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;


@RunWith(JUnitParamsRunner.class)
public class IpAddressValidatorTest {

    private Validator validator;

    @Before
    public void setUp() {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        validator = factory.getValidator();

    }

    public static List<String> goodData() {
        return Arrays.asList(
                "10.10.10.10",
                "127.0.0.1",
                "10.136.182.1",
                "192.168.1.1",
                "192.168.1.1",
                "1.1.1.1",
                "0.0.0.0"
        );
    }

    public static List<String> badData() {
        return Arrays.asList(
                "01.01.01.01",
                "255.255.255.256",
                "127.1",
                "192.168.0.0"
        );
    }

    @Test
    @Parameters(method = "goodData")
    public void ipAddressShouldBeValidated_AndIsValid(String ipAddress) {
        Transaction transaction = new Transaction();
        transaction.setIpAddress(ipAddress);
        Set<ConstraintViolation<Transaction>> violations = validator.validateProperty(transaction, "ipAddress");
        assertTrue(violations.isEmpty());
    }

    @Test
    @Parameters(method = "badData")
    public void ipAddressShouldBeValidated_AndIsNotValid(String ipAddress) {
        Transaction transaction = new Transaction();
        transaction.setIpAddress(ipAddress);
        Set<ConstraintViolation<Transaction>> violations = validator.validateProperty(transaction, "ipAddress");
        assertFalse(violations.isEmpty());
    }


}
0
WesternGun