DEV Community

Erwan Le Tutour
Erwan Le Tutour

Posted on

3

JUnit parameterized tests

test

Parameterized test?

Since JUnit4 we can now run the parameterized test, but what does that mean? It means that we can run one test multiple times with different values, great isn’t it?

How to?

Yeah that great, but how can I do that?
That simple :

  • Annotate your test class with @RunWith(Parameterized.class)

  • Create method annotated with @Parameters that returns an Iterable of Objects as test data set.

  • Create a constructor that takes as a parameter what is equivalent to one row of your dataset. Or create instance variable that will be equivalent as one parameter and annotate them with @Parameter(X) where X is the parameter index in a row of the dataset.

  • Create a test case that will use your instance variable.

Ok, but concretely can I have an example?

Exemple

Class to test

Let’s take a simple class, that take a String literal of a calcul as parameter and return the result.

package fr.eletutour;
public class Operation {
private int left;
private int right;
private String operation;
public Operation(String input){
String[] in = input.split(" ");
this.left = Integer.parseInt(in[0]);
this.right = Integer.parseInt(in[2]);
this.operation = in[1];
}
public int compute(){
switch (operation){
case "plus":
return left + right;
case "minus":
return left - right;
case "divided":
return left / right;
case "by":
return left * right;
default:
throw new IllegalArgumentException("Bad operator");
}
}
}
view raw Operation.java hosted with ❤ by GitHub

Classique Junit test

In a Classique way I wrote this test class to test each one of my case

package com.eletutour;
import fr.eletutour.Operation;
import org.junit.Assert;
import org.junit.Test;
public class OperationTest {
@Test
public void should_return_2_plus(){
Operation op = new Operation("1 plus 1");
Assert.assertEquals(2, op.compute());
}
@Test
public void should_return_6_by(){
Operation op = new Operation("2 by 3");
Assert.assertEquals(6, op.compute());
}
@Test
public void should_return_9_divided(){
Operation op = new Operation("18 divided 2");
Assert.assertEquals(9, op.compute());
}
@Test
public void should_return_5_minus(){
Operation op = new Operation("20 minus 15");
Assert.assertEquals(5, op.compute());
}
@Test(expected = IllegalArgumentException.class)
public void should_throw_exception(){
Operation op = new Operation("20 exp 15");
op.compute();
}
}

As you can see, I have one test per test case, here as my class is simple, it doesn’t have that much line, but what if my class was more complexe, it will be a lot more code, redundant isn’t it?

Parameterized

Here is the same test, but parameterized, you can see all the previous statement established in the How-to section

  • The runner

  • The dataset

  • The parameters

  • The test who use it

    package com.eletutour;
    import fr.eletutour.Operation;
    import org.junit.Rule;
    import org.junit.Test;
    import org.junit.rules.ExpectedException;
    import org.junit.runner.RunWith;
    import org.junit.runners.Parameterized;
    import org.junit.runners.Parameterized.Parameter;
    import org.junit.runners.Parameterized.Parameters;
    import java.util.Arrays;
    import static org.junit.Assert.assertEquals;
    @RunWith(Parameterized.class)
    public class OperationTestParameterized {
    @Parameter(0)
    public String testName;
    @Parameter(1)
    public String input;
    @Parameter(2)
    public int expectedNumber;
    @Parameter(3)
    public Class<? extends Exception> expectedException;
    @Parameter(4)
    public String expectedExceptionMsg;
    @Rule
    public ExpectedException thrown = ExpectedException.none();
    @Parameters(name = "{0}")
    public static Iterable<Object[]> data() {
    return Arrays.asList(new Object[][] {
    // calculation scenarios:
    { "plus compute", "1 plus 1", 2, null, null },
    { "minus compute", "8 minus 3", 5, null, null},
    { "by compute", "3 by 4", 12, null, null},
    { "divided compute", "8 divided 2", 4, null, null},
    { "expected exception", "20 exp 15", 0, IllegalArgumentException.class, "Bad operator"}
    });
    }
    @Test
    public void Operation_compute_test(){
    Operation op = new Operation(input);
    if (expectedException != null) {
    thrown.expect(expectedException);
    thrown.expectMessage(expectedExceptionMsg);
    }
    assertEquals(expectedNumber, op.compute());
    }
    }
    So with one test, I have my 5 previous test cases tested.

Thanks for your reading time, the example in this article are in Junit4, if you want an exemple using Junit5, I will write another article about it.

Image of Datadog

The Future of AI, LLMs, and Observability on Google Cloud

Datadog sat down with Google’s Director of AI to discuss the current and future states of AI, ML, and LLMs on Google Cloud. Discover 7 key insights for technical leaders, covering everything from upskilling teams to observability best practices

Learn More

Top comments (2)

Collapse
 
j143 profile image
Janardhan Pulivarthi

Hi, here is how it is used at SystemDS, github.com/apache/systemds/blob/ma...

Collapse
 
erwanlt profile image
Erwan Le Tutour

thanks, will read it later to improve how i do it.

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay