26
votes

I've googled for JUnit test case, and it comes up with something that looks a lot more complicated to implement - where you have to create a new class that extends test case which you then call:

public class MathTest extends TestCase {
    protected double fValue1;
    protected double fValue2;

    protected void setUp() {
       fValue1= 2.0;
       fValue2= 3.0;
    }
 }

public void testAdd() {
   double result= fValue1 + fValue2;
   assertTrue(result == 5.0);
}

but what I want is something really simple, like the NUnit test cases

[TestCase(1,2)]
[TestCase(3,4)]
public void testAdd(int fValue1, int fValue2)
{
    double result= fValue1 + fValue2;
    assertIsTrue(result == 5.0);
}

Is there any way to do this in JUnit?

6
JUnit has two styles: version 3, which you have in your example, and version 4, which uses annotations. Do you really want to know about version 3? - Raedwald
Ah.. No...I want to know about 4.5... - Steph
I think what I might be looking for is Parameterised Tests. But even this looks a bit verbose and a little bit random... mkyong.com/unittest/junit-4-tutorial-6-parameterized-test - Steph
looks like you can only have 1 parameterised test per class. Shit or what? - Steph
NUnit is derived from JUnit and now it is much advanced than JUnit. TestCase is just one of the example that makes NUnit so easy to use. - Kenneth Xu

6 Answers

13
votes

2017 update: JUnit 5 will include parameterized tests through the junit-jupiter-params extension. Some examples from the documentation:

Single parameter of primitive types (@ValueSource):

@ParameterizedTest
@ValueSource(strings = { "Hello", "World" })
void testWithStringParameter(String argument) {
    assertNotNull(argument);
}

Comma-separated values (@CsvSource) allows specifying multiple parameters similar to JUnitParams below:

@ParameterizedTest
@CsvSource({ "foo, 1", "bar, 2", "'baz, qux', 3" })
void testWithCsvSource(String first, int second) {
    assertNotNull(first);
    assertNotEquals(0, second);
}

Other source annotations include @EnumSource, @MethodSource, @ArgumentsSource and @CsvFileSource, see the documentation for details.


Original answer:

JUnitParams (https://github.com/Pragmatists/JUnitParams) seems like a decent alternative. It allows you to specify test parameters as strings, like this:

@RunWith(JUnitParamsRunner.class)
public class MyTestSuite {
    @Test
    @Parameters({"1,2", "3,4"})
    public testAdd(int fValue1, int fValue2) {
       ...
    }
}

You can also specify parameters through separate methods, classes or files, consult the JUnitParamsRunner api docs for details.

11
votes

Apparently the correct answer is "No, there is no equivalent." And that's sad.

JUnit parameterized tests and theories (as mentioned here and in JUnit - How to test a method with different values?) both can get the job done, but nowhere nearly as cleanly. They are sadly complicated to write, and hard to read.

I hope that one day JUnit can add an easier, NUnit-like syntax. Seems like it shouldn't be that difficult; though perhaps lambdas are needed?

6
votes

It might also be worthwhile to check out JUnit Theories and Datapoints. They let you parametrize tests, but run an all-pairs type combination on your inputs.

5
votes

You can have junit with parameters using zohhak

Usage example:

@RunWith(ZohhakRunner.class)
public class HelloWorldTest {

    @TestWith({
        "2, 1,   3",
        "3, 5,   8"
    })
    public void should_add_numbers(int addend1, int addend2, int result) {

        assertThat(addend1 + addend2).isEqualTo(result);
    }
}
2
votes

It's silly but here is the workaround that I have in the end. Use 4 lines instead one line.

@Test
public void testAdd1() {
    testAdd(1,2);
}
@Test
public void testAdd2() {
    testAdd(3,4);
}
private void testAdd(int fValue1, int fValue2)
{
    double result= fValue1 + fValue2;
    assertIsTrue(result == 5.0);
}
0
votes

I have used a holding class to hold my test cases like this:

class FlexiTest {
String var1;
String var2;
double var3;
String var4;
MyObject var5;
double expected;

public FlexiTest(String var1, String var2, double var3, String var4, MyObject var5, double expected) {
    super();
    this.var1;
    this.var2;
    this.var3;
    this.var4;
    this.var5;
    this.expected = expected;
}

Then setup a stream of my the test class objects like this:

static Stream<FlexiTest> provider(){

    FlexiTest ft1 = new FlexiTest("1", "2", 3, "4", MyObject.A, 1.1);
    FlexiTest ft2 = new FlexiTest("10", "20", 30, "40", MyObject.B, 11);
    FlexiTest ft3 = new FlexiTest("100", "200", 300, "400", MyObject.C, 110);
    
    return Stream.of(ft1, ft2, ft3);
}

Then annotated the Test method with @ParameterizedTest and @MethodSource with the stream of objects method name. Also null and empty checks:

@ParameterizedTest
@MethodSource("provider")   
@NullSource
@EmptySource
public void ClientTest(FlexiTest ft)
{
... my test code ...
}