0

While using parametrized JUnit tests in Eclipse, I'm running into a problem when I want to rerun a single test. The tests themselves run fine, and while I can rerun the first test from the context menu, rerunning the second test:

enter image description here

fails with the following message:

java.lang.Exception: No tests found matching [{ExactMatcher:fDisplayName=test[1: A2 --> [Ljava.lang.String;@1e4a7dd4]], {ExactMatcher:fDisplayName=test[1: A2 --> Ljava.lang.String;@1e4a7dd4]] from org.junit.internal.requests.ClassRequest@6c3f5566

enter image description here

I'm pretty sure this is because JUnit doesn't 'like' my arrays; for some context: I'm using this to account for the fact that due to external circumstances, the code under test can produce one of two outcomes for a particular test case.

Here is some code to reproduce this:

package com.stackexchange.toolbox;

import java.util.ArrayList;
import java.util.Arrays;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)
public class Tester {
    public Tester(String source, Object target) {
        this.source = source;
        this.target = target;
    }

    private final String source;
    private final Object target;

    private static final Object[][] testCases = { { "A1", "B1" }, { "A2", new String[] { "B2", "C2" } } };

    @Parameters(name = "{index}: {0} --> {1}")
    public static Iterable<Object[]> data() throws Exception {
        return new ArrayList<>(Arrays.asList(testCases));
    }

    @Test
    public void test() throws Exception {
        if (target instanceof String) {
            Assert.assertEquals(source.charAt(1), ((String)target).charAt(1));
        } else {
            for (String target : (String[])this.target) {
                Assert.assertEquals(source.charAt(1), target.charAt(1));
            }
        }
    }
}

Is there an easy way to fix this, perhaps with Lists or variadic arguments? Most of the (100+) test cases are simple 'source', 'target' entries, and I'd like to keep the conciseness of { "A1", "B1" }.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109

1 Answers1

1

This seems to be a limitation of JUnit4 (at least you get the same error on the command line).

The simplest and straightforward solution would be to migrate from JUnit4 to JUnit5, which would also mean less code:

package com.stackexchange.toolbox;

import java.util.Arrays;
import java.util.stream.Stream;

import org.junit.Assert;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

class Tester {
    
    private static final Object[][] testCases = { { "A1", "B1" }, { "A2", new String[] { "B2", "C2" } } };

    @ParameterizedTest(name = "{index}: {0} --> {1}")
    @MethodSource("provideArguments")
    void test(String source, Object target) {
        if (target instanceof String) {
            Assert.assertEquals(source.charAt(1), ((String)target).charAt(1));
        } else {
            for (String targetElement : (String[])target) {
                Assert.assertEquals(source.charAt(1), targetElement.charAt(1));
            }
        }
    }

    static Stream<? extends Arguments> provideArguments() throws Exception {
        return Arrays.stream(testCases).map(Arguments::of);
    }

}
howlger
  • 31,050
  • 11
  • 59
  • 99
  • That works, thanks! I do miss one feature of the old setup: then it immediately became apparent how many test cases there were (and you could cancel the test and run a specific one). Right now, they're streamed and added one by one, it seems. The actual tests cost several seconds, so that is not ideal. – Glorfindel Mar 20 '22 at 19:26
  • I see, but I can't think of a solution to this. Unfortunately, this is the same for [dynamic tests](https://www.baeldung.com/junit5-dynamic-tests). Maybe you can ask this as a separate question. As workaround for the total number you can add a third parameter, so you can do `name = "{index}/{2}: {0} --> {1}"`. – howlger Mar 21 '22 at 08:19