I can really use some help with this parameterized test case I am trying to create. No matter what kind of constructor I create the IDE gives an error message. Here is my code:
@RunWith(Parameterized.class) public class SolverTest { final static File folder = new File("C:\Users\Azizam\IdeaProjects\EightPuzzle\src\ModifiedTests"); final static String destFolder = "C:\Users\Azizam\IdeaProjects\EightPuzzle\src\testresults"; final static ArrayList<Object[][]> filesList = new ArrayList<>(); final Object currentBoard = new Object(); @Parameterized.Parameters public static Iterable<Object[][]> data() { String path = ""; int counter = 0; for (final File fileEntry : folder.listFiles()) { //System.out.println("processing file: " + fileEntry.getName()) counter++; if (counter == 20) break; path = destFolder + fileEntry; In in = new In(fileEntry.getAbsolutePath()); int n = in.readInt(); int moves = in.readInt(); int[][] tiles = new int[n][n]; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) tiles[i][j] = in.readInt(); Board b = new Board(tiles); Object[][] fileList = new Object[][]{{b, moves}}; filesList.add(fileList); } return filesList; } @Parameterized.Parameter(0) private Board board; @Parameterized.Parameter(1) private int expectedNumberOfMoves; public SolverTest(Board board, int expectedNumberOfMoves) { this.board = board; this.expectedNumberOfMoves = expectedNumberOfMoves; } @Test public void test() { assertEquals(expectedNumberOfMoves, new Solver(board).moves()); } }
I have tried different ways of creating a 1 parameter, 2, and no parameter constructors. But I have never seen this type of issue or what the solution might be. I am following this link and this tutorial. This is my first parameterized test, and debug does not seem to provide much for me either. I also saw these links, but they did not help. I can provide the code for the rest of the project also on GitHub or gist. I did debug my code through creating the fileList properly, but I know little about what happens to it afterwards or what needs to happen. Here is an excerpt of the error:
java.lang.Exception: Test class should have exactly one public zero-argument constructor at org.junit.runners.BlockJUnit4ClassRunner.validateZeroArgConstructor(BlockJUnit4ClassRunner.java:171) at org.junit.runners.parameterized.BlockJUnit4ClassRunnerWithParameters.validateConstructor(BlockJUnit4ClassRunnerWithParameters.java:90) at org.junit.runners.BlockJUnit4ClassRunner.collectInitializationErrors(BlockJUnit4ClassRunner.java:127) at org.junit.runners.ParentRunner.validate(ParentRunner.java:416) at org.junit.runners.ParentRunner.<init>(ParentRunner.java:84) at org.junit.runners.BlockJUnit4ClassRunner.<init>(BlockJUnit4ClassRunner.java:65) at org.junit.runners.parameterized.BlockJUnit4ClassRunnerWithParameters.<init>(BlockJUnit4ClassRunnerWithParameters.java:27) at org.junit.runners.parameterized.BlockJUnit4ClassRunnerWithParametersFactory.createRunnerForTestWithParameters(BlockJUnit4ClassRunnerWithParametersFactory.java:16) at org.junit.runners.Parameterized.createRunnersForParameters(Parameterized.java:313) at org.junit.runners.Parameterized.<init>(Parameterized.java:248) at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490) at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:104) at org.junit.vintage.engine.discovery.DefensiveAllDefaultPossibilitiesBuilder$DefensiveAnnotatedBuilder.buildRunner(DefensiveAllDefaultPossibilitiesBuilder.java:113)
Here is the latest version of my code:
package assignments; import edu.princeton.cs.algs4.In; import org.junit.jupiter.api.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import java.io.File; import java.util.ArrayList; import static junit.framework.TestCase.assertEquals; @RunWith(Parameterized.class) public class SolverTest { final static File folder = new File("C:\Users\Azizam\IdeaProjects\EightPuzzle\src\ModifiedTests"); final static String destFolder = "C:\Users\Azizam\IdeaProjects\EightPuzzle\src\testresults"; final static ArrayList<Object[][]> filesList = new ArrayList<>(); final Object currentBoard = new Object(); @Parameterized.Parameters public static Iterable<Object[][]> data() { String path = ""; int counter = 0; for (final File fileEntry : folder.listFiles()) { //System.out.println("processing file: " + fileEntry.getName()) counter++; if (counter == 20) break; path = destFolder + fileEntry; In in = new In(fileEntry.getAbsolutePath()); int n = in.readInt(); int moves = in.readInt(); int[][] tiles = new int[n][n]; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) tiles[i][j] = in.readInt(); Board b = new Board(tiles); Object[][] fileList = new Object[][]{{b, moves}}; filesList.add(fileList); } return filesList; } @Parameterized.Parameter(0) public Board board; @Parameterized.Parameter(1) public int expectedNumberOfMoves; public SolverTest() { } @Test public void test() { assertEquals(expectedNumberOfMoves, new Solver(board).moves()); } }
Here is a pic of the debug session showing everything I want in the file list. Some how the board object does not transfer to my Solver constructor.
Advertisement
Answer
Here is what the no-arg constructor error means.
The constructor in the test class is the following:
public SolverTest(Board board, int expectedNumberOfMoves) { this.board = board; this.expectedNumberOfMoves = expectedNumberOfMoves; }
That takes 2 arguments, so is not a no-arg constructor. The following is a no-arg constructor:
public SolverTest() { }
Removing the 2-arg constructor will work, so this does not need to be explicitly listed, because the java compiler will add the default no-arg constructor automatically.
HOWEVER the reason for the error is a mix of 2 approaches for the Parameterized
test class.
EITHER use a no-arg constructor with the @Parameterized.Parameters
fields (which need to be public and not private, by the way), OR remove those fields and use the construct with arguments that take the parameters.
Here is the code modified to use the first approach (that is, with the @Parameterized.Parameters
fields):
@RunWith(Parameterized.class) public class SolverTest { final static File folder = new File("C:\Users\Azizam\IdeaProjects\EightPuzzle\src\ModifiedTests"); final static String destFolder = "C:\Users\Azizam\IdeaProjects\EightPuzzle\src\testresults"; final static ArrayList<Object[][]> filesList = new ArrayList<>(); final Object currentBoard = new Object(); @Parameterized.Parameters public static Iterable<Object[][]> data() { String path = ""; int counter = 0; for (final File fileEntry : folder.listFiles()) { //System.out.println("processing file: " + fileEntry.getName()) counter++; if (counter == 20) break; path = destFolder + fileEntry; In in = new In(fileEntry.getAbsolutePath()); int n = in.readInt(); int moves = in.readInt(); int[][] tiles = new int[n][n]; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) tiles[i][j] = in.readInt(); Board b = new Board(tiles); Object[][] fileList = new Object[][]{{b, moves}}; filesList.add(fileList); } return filesList; } @Parameterized.Parameter(0) public Board board; @Parameterized.Parameter(1) public int expectedNumberOfMoves; public SolverTest() { } @Test public void test() { assertEquals(expectedNumberOfMoves, new Solver(board).moves()); } }