Creating Dynamic .CSV Files in Cucumber Using .VM templates

Have you ever got into a situation while testing where you had to automate creation of a .CSV file and upload it on to the system? One way of doing this is to create a separate Cucumber step that does that for you, however, it’s a very static and clunky solution that required for you to create a new step every-time you want to change or edit the structure of the .CSV file. Also, you don’t have the freedom of parameterizing the document, values have to be preset or in a best-case very few fields can be parameterized.

Luckily there is a solution to this problem, using .VM templates you can create a dynamic .csv files on the go in the .feature file. This gives you all the control in the world over .csv file creation and population inside of the feature file. These are the simple steps that allow you to achieve this solution:

  • Create a .VM template file with expected structure of the .csv
  • Create a step in cucumber which takes in your desired data set and the template
  • Using the template and data set, create a .csv file.

Bellow are some snippest that can be utilized to achieve this solution:

.VM template example:

Example_1,Example_2,Example_3
#foreach($c in $o)
#set ($example1 = $c.getOrDefault('example1','1'))
#set ($example2 = $c.getOrDefault('example2','1'))
#set ($example3 = $c.getOrDefault('example3','1'))
$example1,$example2,$example3
#end

This is how this whole solution looks like in the feature file, just pass a template file and create a cucumber table which will be used to generate a .csv file with whatever values you want. One method will cater for all .csv related functions.

And I define the following user defined variables:
    | ranNum1   | $js{ranNum = Math.floor((Math.random() * Math.pow(10,4)) + 1).toString();} |

And I update the below list of values in the template file "data/data_loaders/idr/idr_template.vm" and save it in file "/target/IDR/<dataFile>":
    | example1                  | example2 		   | example3       |
    | VALUE_1_${ranNum1}  	| VALUE_2                  | VALUE3  		| 

This is my example implementation of Cucumber step, which takes in a template, data table and generates a .csv file in a target location. This method can be used in any .csv file creation.

    @And("^I update the below list of values in the template file \"([^\"]*)\" and save it in file \"([^\"]*)\":$")
    public void iUpdateTheBelowListOfValuesInTheTemplateFileAndSaveItInFile(StepParam templateFile, StepParam targetFile, List<Map<StepParam, StepParam>> dataTable ) throws Throwable {

        List<Map<String,String> > values = new ArrayList<>();
        dataTable.forEach(stepParamStepParamMap -> {
            Map<String,String> map = new LinkedHashMap<>();
            stepParamStepParamMap.forEach((k,v)-> map.put(k.val(),v.val()));
            values.add(map);
        });
        String value = TemplaterUtil.getValueAfterReplacing(templateFile.val(),values );
        FileUtils.write(new File(userDir + targetFile.val()),value,false);
        PluginUtils.moveFilesToCrucialFilesFolder( userDir + targetFile.val());
    }
	

A further implementation of how to use .VM template.

public static String getValueAfterReplacing(String filePath, Object object) throws Exception {
        VelocityEngine engine = new VelocityEngine();
        engine.init();
        Template template = engine.getTemplate(filePath);
        VelocityContext vc = new VelocityContext();
        vc.put("o", object);
        StringWriter writer = new StringWriter();
        template.merge(vc, writer);
        return writer.toString();
    }

That’s a quick solution to all of your .csv testing problems. No need to build an excel file using Apache POI, and having so many different methods to cover all scenarios. Just create a quick template file and define the data directly in the feature file.

Also, this can be utilized when creating .XML files as well!

Leave a comment