Question

@DataPoints public static final Integer[] input1={1,2};
@Theory
@Test
public void test1(int input1){

}

@DataPoints public static final Integer[] input2={3,4};
@Theory
@Test
public void test2(int input2 ){

}

I want that test1 runs with data set input1 - {1,2} and test2 runs with input2 - {3,4}. But currently each test runs with both the data sets {1,2,3,4}. How to bind specific @DataPoints to specific @Theorys

Was it helpful?

Solution

DataPoints apply to the class. If you have a @Theory method which takes an int, and you have a DataPoint which is an array of ints, then it will be called with the int.

@RunWith(Theories.class)
public class TheoryTest {
    @DataPoint public static int input1 = 45;
    @DataPoint public static int input2 = 46;
    @DataPoints public static String[] inputs = new String[] { "foobar", "barbar" };

    @Theory public void testString1(String input) {
        System.out.println("testString1 input=" + input);
    }

    @Theory public void testString2(String input) {
        System.out.println("testString2 input=" + input);
    }

    @Theory public void test1(int input) {
        System.out.println("test1 input=" + input);
    }

    @Theory public void test2(int input) {
        System.out.println("test2 input=" + input);
    }
}

This calls test1 with 45 & 46, and test2 with 45 & 46. It calls testString1 with "foobar" and "barbar" and testString2 with "foobar" and "barbar".

If you really want to use different data sets for different theories, you can wrap the data in a private class:

@RunWith(Theories.class)
public class TheoryTest {
    public static class I1 { int i; public I1(int i) { this.i = i;} }
    public static class I2 { int i; public I2(int i) { this.i = i;} }

    @DataPoint public static I1 input1 = new I1(45);
    @DataPoint public static I2 input2 = new I2(46);

    @Theory
    public void test1(I1 input) {
        System.out.println("test1 input=" + input.i);
    }

    @Theory
    public void test2(I2 input) {
        System.out.println("test2 input=" + input.i);
    }
}

This calls test1 with 45 and test2 with 46. This works, but in my opinion, it obscures the code, and it may be a better solution to just split the Test class into two classes.

OTHER TIPS

With JUnit 4.12 (not sure when it was introduced) it is possible to name the DataPoints and assign them to parameters (i learned it from http://farenda.com/junit/junit-theories-with-datapoints/):

    @RunWith(Theories.class)
    public class TheoriesAndDataPointsTest {
        @DataPoints("a values")
        public static int[] aValues() {
            return new int[]{1, 2};
        }

        @DataPoints("b values")
        public static int[] bValues() {
            return new int[]{3, 4};
        }

        @Theory
        public void theoryForA(@FromDataPoints("a values") int a) {
            System.out.printf("TheoryForA called with a = %d\n", a);
        }

        @Theory
        public void theoryForB(@FromDataPoints("b values") int a) {
            System.out.printf("TheoryForB called with b = %d\n", a);
        }
    }

Output:

TheoryForA called with a = 1
TheoryForA called with a = 2
TheoryForB called with b = 3
TheoryForB called with b = 4

In reference to Gábor Lipták's answer, named datapoints can be defined as a static fields (reference) which give us more concise code:

    @RunWith(Theories.class)
    public class TheoriesAndDataPointsTest {
        @DataPoints("a values")
        public static int[] aValues = {1, 2};

        @DataPoints("b values")
        public static int[] bValues = {3, 4};

        @Theory
        public void theoryForA(@FromDataPoints("a values") int a) {
            System.out.printf("TheoryForA called with a = %d\n", a);
        }

        @Theory
        public void theoryForB(@FromDataPoints("b values") int a) {
            System.out.printf("TheoryForB called with b = %d\n", a);
        }
    }

Some of the references I have seen talking about using tests for specific values and theories for verifying behavior. As an example, if you have a class that has methods to add and subtract from an attribute, a test would verify correctness of the result (e.g., 1+3 returns 4) whereas a theory might verify that, for the datapoint values (x1, y1), (x2, y2), x+y-y always equals x, x-y+y always equals x, x*y/y always equals x, etc. This way, the results of theories are not coupled as tightly with the data. With theories, you also can filter out cases such as y == 0; they don't count as failure. Bottom line: you can use both. A good paper is: http://web.archive.org/web/20110608210825/http://shareandenjoy.saff.net/tdd-specifications.pdf

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top