5.4. Using dedicated data generators

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:

  • Strings (each iteration will fetch a character).
  • Maps (each iteration will pick a key).
  • Enumerations.
  • Arrays.
  • RegEx matchers.
  • Iterators.
  • Iterables.

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.

Figure 5.15. All solutions shown for parameterized Spock tests. Data tables are limited, but readable by even nontechnical people. All other techniques sacrifice readability for more expressive power.

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.

Figure 5.16. Using a text file as a data source for a parameterized test

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.

Listing 5.18. Using existing data generators

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.

Figure 5.17. Reading test values from a file by using Groovy code

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).

9

Or even classes from Guava, Apache commons, CSV reading libraries, and so on.

5.4.1. Writing a custom data generator

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]

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.

Listing 5.19. Java iterator that processes invalidImageNames.txt

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.

Listing 5.20. Using Java iterators in Spock

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.

Figure 5.18. Using a Java iterator in a Spock unit test allows for more fine-grained file reading.

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.

Writing custom data generators in Groovy

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).

5.4.2. Using multivalued data iterators

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:

11

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.

12

You can find more details about Groovy multivalue assignments at http://www.groovy-lang.org/semantics.html#_multiple_assignment.

Listing 5.21. Java multivalued iterator

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.

Listing 5.22. Using multivalued iterators in Spock

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.

Figure 5.19. Multivalued iterators. For each test run, Spock reads both the input (image filename) and the output parameter (result of validity) from the data file.

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.

Listing 5.23. Using multivalued assignments in Spock

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.21.106.7