Looping in Gherkin
I am aware of the debate over Cucumber not being a testing framework, it is about "What" and not "How"; that it is for business perspective instead of a testing perspective. Here is (kindof) what our Business Analyst gave us as a preliminary story (after we gave him a demo on Cucumber, which he *loved* BTW):
Given: The Customer wants an 'X'
When: The User collects the ingredients to make 'X'
Then: The User must have all the ingredients to make 'X' in one place.
When: The user has all the tools to make "X"
Then: The user must confirm that all the tools needed to make "X" are in READY status
<another 200 steps later>
When User delivers 'X' to Customer
Then User is happy with 'X'
Where X can be "Cake", "B2 Bomber", and everything in-between. It is expected to use the same high-level process for making and delivering any X, though the "How" details are taken care of inside the step definition files and the application itself..
My problem is with the best way to do exhaustive testing. I have 1000 different input records, 30 columns long (in an Excel file) to feed to the application web site, as each X can have wildly different options, too. I can process each record in the Excel file because all are processed basically the same way (at a high level), though the application's back end often hits the DB to figure out the details that figure out the correct response (which is also encoded in my Excel data file). I use an Excel spread sheet instead of Gherkin "in-file" data input tables because that way the data only needs to be in one place (for version control). Besides, it's also used for other things.
I have no problem getting to the Excel file. To run a different input data set, all I need to do is to change one global variable in my java definition file - the index to the row number of the Excel file.
I can either do that manually 1000 times, or I can copy and paste the same 220-line gherkin file into 1000 different files.
I suppose I could write a Java-copying program that does exactly that, with the index incremented each time. But that just seems so wrong. I think the correct way to do it is with hooks. Does anyone know how to do that?
Nobody replied with a solution (I was hoping for one using hooks), but I figured one out anyway.
To repeat a cucumber test with different input data, you can do something like this (your maven may live in a different place, as will your project):
public static void main(String[] args) {
String dosCommand = "C:\\workarea\\Maven\\apache-maven-3.3.3\\bin\\mvn.cmd test -Dcucumber.options=\"--tags @tag\"";
String directoryName = "C:\\Users\\ttoth\\workspace\\looper\\";
System.out.println("Starting Repeater.main: " + dosCommand + " at directory: " + directoryName);
for (int i=0; i<3; i++) {
writeFile(directoryName + "index.txt", i + "\n");
System.out.println(i + ". Repeater.main: executing " + dosCommand);
runDosCommand(dosCommand, directoryName);
String filename = "index.txt";
System.out.println("Repeater.main: file " + filename + ": " + readFile(directoryName + filename, true));
filename = "target\\surefire-reports\\TEST-com.abc.cuke.looper.AppTest.xml";
String xmlContents = readFile(directoryName + filename, true);
int begin = xmlContents.indexOf("<testsuite");
int end = xmlContents.indexOf(">", begin);
System.out.println("main: file " + filename + ": " + xmlContents.substring(begin, end).replace("name=\"", "\nname=\""));
}
}Where:
public static String runDosCommand(String command, String directoryPath) {
System.out.println("runDosCommand: " + command + " at " + directoryPath);
String result = "";
try {
String[] envp = null;
File directory = new File(directoryPath);
Process process = Runtime.getRuntime().exec(command, envp, directory);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String standardOutput;
System.out.println("Standard output: ");
while ((standardOutput = stdInput.readLine()) != null) {
System.out.println(standardOutput);
result = result + standardOutput + "\n";
}
if (stdError.ready()) { System.err.println("Standard error: "); }
while ((standardOutput = stdError.readLine()) != null) {
System.err.println(standardOutput);
result = result + standardOutput + "\n";
}
} catch (Exception ex) {
System.err.println("Failed. Repeater.runCommand command failed (" + command + "). "+ ex.getMessage());
ex.printStackTrace(System.err);
}
return result;
}
public static void writeFile(String fileName, String text) {
try (BufferedWriter bw = new BufferedWriter(new FileWriter(fileName))) {
bw.write(text);
System.out.println("Finished writing to file " + fileName);
} catch (IOException e) {
e.printStackTrace();
}
}
public static String readFile(String pathWithFileName, boolean quietFlag) {
File file = new File(pathWithFileName);
String line;
StringBuilder stringBuilder = new StringBuilder("");
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))){
while ((line = bufferedReader.readLine()) != null) {
if (!quietFlag) { System.out.println(line); }
stringBuilder.append(line).append("\n");
}
} catch (IOException ex) {
System.err.println("Error. Could not read file '"+ pathWithFileName + ". " + ex.getMessage());
ex.printStackTrace();
}
return stringBuilder.toString();
}