Fill Multi-Variable Data Pipes for Groovy Spock tests from a file


Create Multi-Variable Data Pipes for Groovy Spock tests in a method

This article describes why and how to fill multi-variable data pipes with data from a file in a Spock Groovy test. The Spock framework is a handy tool to write meaningful and concise tests for Java projects.

The tests are structured according to the following pattern:

  • given
  • when
  • then
  • where

Especially the optional where part is very interesting. This allows a set of expected test values to be set in tabular form. So it is possible to create "parameterized tests":

def "Get weight at one date with parameterized tests"() {
    given: "Repository with Testdata"
    WeightDataRepository dataRepository = Mock(WeightDataRepository)
    dataRepository.findByDate(date) >> new WeightData(weight, date)
    WeightService weightService = new WeightService(dataRepository);

    when: "WeightService is created and lines are read"
    float weightFromDate = weightService.getWeightFromDate(date)

    then: "The weight at this day"
    weightFromDate == weight
    where: "Load data"
    weight | date
    80.3f  | LocalDate.of(2017, 8, 23)
    80.5f  | LocalDate.of(2017, 8, 24)
    80.3f  | LocalDate.of(2017, 8, 25)

In the example, a test is performed with three test records. The condition in the then part is checked for all parameters from the where part. Already in this trivial example it can be seen that in the long run it is unpleasant to maintain the table with the parameters. Especially if the test data should be used for several tests. Therefore, filling the multi-variable data pipe should be swapped out into a method. Behind the weight | date table is nothing more than an ArrayList with pairs of a float and a LocalDate.

where: "Load data"
     // ArrayList [Float, LocalDate]
     [weight, date] << getTestdata()

The method getTestdata() looks like this:

def getTestdata() {
     return [[80.3f, LocalDate.of(2017, 8, 23)], [80.5f, LocalDate.of(2017, 8, 24)]]

In the next step, the test data should be extracted to a file:

    def getTestdataFromFile() {

        String testdata = new File("src/test/resources/Testdata.txt").text
        ArrayList data = [];

        List<String> lines = testdata.tokenize("\n")

        for (String line : lines) {
            float weight = Float.parseFloat(line.substring(0, 4).replace(',','.'));
            def date = line.substring(5) + "2017";
            data.add([weight, LocalDate.parse(date,DateTimeFormatter.ofPattern('dd.M.yyyy'))])
        return data

The file (Testdata.txt) has the following format and I assume that it is data from the year 2017:

 80,3 23.8.
 80,5 24.8.
 80,3 25.8.

However, it is possible to write the method more compactly:

def getTestdataFromFileShort() {
    ArrayList data = [];
    new File("src/test/resources/Testdata.txt").text.eachLine {line->data.add([Float.parseFloat(line.substring(0, 4).replace(',','.')), LocalDate.parse(line.substring(5) + "2017",DateTimeFormatter.ofPattern('dd.M.yyyy'))]) }

    return data

In this way, it is easy to extend the test data in the file without any effort and to use it in various tests.

The source code to be tested can be found in the following Github project: