All the previous examples of data pipes use lists (Groovy ranges also act as lists) to hold the parameters for each test iteration. Grouping parameters in a list is the more readable option in my opinion, but Spock can also iterate on the following:
This list isn’t exhaustive. Everything that Groovy can iterate on can be used as a data generator. Chapter 2 even includes a Groovy Expando as an example of an iterator. Iterables and iterators are interfaces, which means that you can implement your own classes for the greatest control of how Spock uses parameters. Even though custom implementations can handle complex transformations of test data when required, I consider them a last-resort solution because they’re not always as readable as simpler data tables. The solutions offered by Spock are compared in figure 5.15.
If you need to create a custom iterator for obtaining business data, you should always ask yourself whether the transformation of the data belongs in the business class that you’re trying to test, or whether it’s part of the iterator.
Before trying custom iterators, you should spend some time determining whether you can use existing classes in your application that already return data in the format that you expect. As an example, assume you have a text file that holds image names that your program can accept, as shown in figure 5.16.
The content of the file validImageNames.txt is as follows:
hello.jpg another.jpeg modern0034.JPEG city.Png city_004.PnG landscape.JPG
To read this file, you don’t need a custom iterator. The Groovy File class already contains a readLines() method that returns a list of all lines in a file. The respective Spock test is shown in the following listing.
Here Groovy opens the file, reads its lines in a list, and passes them to Spock. Spock fetches the lines one by one to create all the scenarios of the test. Running the test produces the output shown in figure 5.17.
Before resorting to custom iterators, always see whether you can obtain data with your existing application code or GDK/JDK facilities.[9] Always keep in mind the excellent facilities of Groovy for XML and JSON reading (these were covered in chapter 2).
Or even classes from Guava, Apache commons, CSV reading libraries, and so on.
You show the unit test with the valid image names to your business analyst in order to explain what’s supported by the system. The analyst is impressed, and as a new task, you get the following file named invalidImageNames.txt:
#Found by QA starsystem.tiff galaxy.tif #Reported by client bunny04.gif looper.GIF dolly_take.mov afar.xpm
The file can’t be used as is in a unit test. It contains comments that start with the # sign, it has empty lines, and it even has tabs in front of some image names.
You want to write a Spock test that checks this file and confirms the rejection of the image names (they’re all invalid). It’s obvious that the Groovy File class can’t help you in this case; the file has to be processed before it’s used in the Spock test.[10]
In this simple example, you could clear the file contents manually. In a larger file, this isn’t practical or even possible.
To solve this new challenge, you should first create a custom data iterator, as shown in the next listing.
There’s nothing Spock-specific about this class on its own. It’s a standard Java iterator that reads the file and can be used to obtain string values. You can use this iterator directly in Spock, as shown in the next listing.
If you run this test, you’ll see that the file is correctly cleaned up and processed, as shown in figure 5.18. Empty lines, comments, and tabs are completely ignored, and only the image names are used in each test scenario.
Happy with the result, you show the new test to your business analyst (thinking that you’re finished). Apparently, you must face one last challenge.
In this section and the next, I use Java to implement a custom data generator because I assume that you’re more familiar with Java. It’s possible to write data generators in Groovy. This would be the preferred method when you know your way around Groovy, because you can include the generator inside the same source file as the Spock test (instead of having two separate files, one in Java for the iterator and one in Groovy for the Spock test).
Your business analyst examines the two Spock tests (the one for valid images, and the one for invalid images) and decides that two files aren’t needed. The analyst combines the two files into one, called imageNames.txt, with the following content:
#Found by QA starsystem.tiff fail galaxy.tif fail desktop.png pass europe.jpg pass modern0034.JPEG pass city.Png pass city_004.PnG pass #Reported by client bunny04.gif fail looper.GIF fail dolly_take.mov fail afar.xpm fail
This file is similar to the other two, with one important difference. It contains the word pass/fail in the same line as the image name.[11] At first glance, it seems that you need to write a test similar to listing 5.13, but using two custom iterators, as follows:
In reality, this file would be a large XLS file with multiple columns that contained both important and unrelated data.
where: "sample image names are" pictureFile << new CustomIterator1() validPicture << new CustomIterator2()
The first iterator is responsible for reading the image names as before, and the second iterator reads the pass/fail flag and converts it to a Boolean. This solution would certainly work, but having two custom iterators isn’t practical. They would both share similar code (both need to ignore empty lines), and keeping them in sync if the file format changed would be a big challenge.
Hopefully, with Spock tests you don’t need extra custom iterators for each parameter. Spock supports multivalue iterators (powered by Groovy multivalued assignments[12]), so you can obtain all your input/output parameters from a single iterator. For illustration purposes, our example uses a custom iterator to fetch two variables, but the same technique can work with any number of parameters. The iterator is shown in the next listing.
You can find more details about Groovy multivalue assignments at http://www.groovy-lang.org/semantics.html#_multiple_assignment.
Here the defined iterator returns two objects. The first object is the image name, and the second object is a Boolean that’s true if the image should be considered valid, and false if the image name should be rejected. Notice again that there’s nothing Spock-specific about this class. It’s a normal Java class.
The Spock test that uses this multivalue iterator is shown in the following listing.
In the Spock test, the left-shift operator is used as before, but this time the left side is a list of parameters instead of a single parameter. Spock reads the respective values from the data generator and places them in the parameters in the order they’re mentioned. The first value that comes out of the data generator is placed in the first parameter (the image name, in this case), and the second value from the generator (the Boolean flag, in this case) is placed in the second parameter. Running the test produces the output in figure 5.19.
This capability of the left-shift operator to handle multivalues isn’t restricted to data generators (although that’s where it’s most useful). You can perform multivalue parameter assignments by using plain data pipes, as shown in the following listing.
The right side of the assignment contains a list of all scenarios (which are lists). For each scenario, Spock again picks the first element and places it in the first variable of the left list. The second element from the scenario is placed in the second parameter, and so on.
3.21.106.7