budi
budi

Reputation: 6551

How do I run the same test with multiple inputs?

I want to do a batch test like the following, however if there is an error, it does not tell me which value of i the error occurs in.

@Test
public void simpleMovingAverageBatch() {
    for (int i = 1; i < 61; ++i) {
        simpleMovingAverage(i);
    }
}

public void simpleMovingAverage(int days) {
    double sma = -1;
    int size = stock.getCloses().size();

    stock.calcSMA(days); // <- code that I'm testing

    // first days should be -1
    for (int index = size - 1; index >= size - days + 1; --index) {
        assertEquals(-1, stock.getSMA(days, index), 0.001);
    }

    for (int index = size - days - 1; index >= 0; --index) {
        sma = 0.0;
        for (int i = 0; i < days; ++i) {
            sma += stock.getCloses().get(index + i);
        }
        sma /= days;
        assertEquals(sma, stock.getSMA(days, index), 0.001);
    }
}

This is an example of what happens if I run the code as is:

Not what I want!

This is an example of what I want to have happen:

Something like this!

I've taken a look at Parameterized Tests in this tutorial, however I do not know if this the route I want to take.

Any tips?


I don't think this question is a duplicate of these:

Running the same JUnit test case multiple time with different data

Java unit test for different input data

Upvotes: 4

Views: 4338

Answers (3)

Andreas
Andreas

Reputation: 5093

Durron's answer leads to parameterized JUnit tests via @Parameters. This is a great answer and fits the question perfectly. However, I've been down that road and found it created complicated and hard to read tests.

Theories are an alternative within JUnit: https://github.com/junit-team/junit4/wiki/Theories

If you are willing to stray from JUnit, testNG's dataproviders are quite versatile: https://testng.org/#_parameters_with_dataproviders

Upvotes: 2

Alex Borysov
Alex Borysov

Reputation: 281

Try JUnitParams. Your test will look like:

@RunWith(JUnitParamsRunner.class)
public class ExampleTest {

    // this method provides parameters for simpleMovingAverage
    public static Iterable<Integer> parametersForSimpleMovingAverage() {
        return IntStream.rangeClosed(1, 61).boxed().collect(Collectors.toList());
    }

    @Parameters
    @Test
    public void simpleMovingAverage(int days) {
        double sma = -1;
        int size = stock.getCloses().size();

        stock.calcSMA(days); // <- code that I'm testing

        // first days should be -1
        for (int index = size - 1; index >= size - days + 1; --index) {
            assertEquals(-1, stock.getSMA(days, index), 0.001);
        }

        for (int index = size - days - 1; index >= 0; --index) {
            sma = 0.0;
            for (int i = 0; i < days; ++i) {
                sma += stock.getCloses().get(index + i);
            }
            sma /= days;
            assertEquals(sma, stock.getSMA(days, index), 0.001);
        }
    }

And when you run the test, you will have a report like you wanted to have. Even better, unlike standard JUnit Parametrized runner JUnitPramsRunner report will contain not only test case index, but the parameter for each case (sorry, I have not enough reputation to post a screenshot).

Note: you will need to add a dependency:

  • Gradle:

    testCompile 'pl.pragmatists:JUnitParams:1.0.2'
    
  • Maven:

    <dependency>
      <groupId>pl.pragmatists</groupId>
      <artifactId>JUnitParams</artifactId>
      <version>1.0.4</version>
      <scope>test</scope>
    </dependency>
    

Upvotes: 2

durron597
durron597

Reputation: 32323

The right way to do this test is to use a parameterized test as you describe in your question. However, you said you don't want to do that. So, instead, you can always use the String message argument for your failure message.

You appear to be using assertEquals(double, expected, double actual, double delta) in this line:

assertEquals(-1, stock.getSMA(days, index), 0.001);

Instead, you could use assertEquals(String message, double expected, double actual, double delta) to give yourself a more informative error message, e.g.

assertEquals(String.format("For index %d,", index), -1, stock.getSMA(days, index), 0.001);

This will give you an error message like:

java.lang.AssertionError: For index 15, expected:<-1.0> but was:<0.0>

Upvotes: 3

Related Questions