Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Kenneth A. Kousen - Making Java Groovy - 2014.pdf
Скачиваний:
50
Добавлен:
19.03.2016
Размер:
15.36 Mб
Скачать

Testing scripts written in Groovy

137

(continued)

3Version 4 tests do not have a superclass. Instead, all of the assert methods are static methods in the org.junit.Assert class.

4By the Groovy truth, assert, assertTrue, and assertNotNull are all the same.

5Because the Groovy assert provides so much debugging information when it fails, it’s normally preferred over the standard JUnit assertEquals methods.

6GroovyTestCase extends TestCase from JUnit and adds a handful of convenience methods, like assertLength and shouldFail.

Testing a script written in Groovy involves special circumstances, especially if input data is supplied from outside. That’s the subject of the next section.

6.2Testing scripts written in Groovy

Testing scripts is a bit different from testing classes. You don’t normally instantiate a script and call a method on it, although you can. Instead, it’s easiest just to execute the script and let its own internal assert statements do any correctness checks.

USING ASSERT When Groovy developers write scripts, they typically add asserts to demonstrate that the script works properly.

Running a script inside a test case is easy enough if no input or output variables are involved. Because scripts normally contain assert statements that verify their correctness, the key is simply to execute the script programmatically. That’s what the GroovyShell class is for.

Here’s a simple example. Consider a short but powerful script that accesses the Internet Chuck Norris Database,6 reproduced from chapter 4:

import groovy.json.JsonSlurper

def result = 'http://api.icndb.com/jokes/random'.toURL().text def json = new JsonSlurper().parseText(result)

def joke = json?.value?.joke assert joke

println joke

This script, when executed, accesses the RESTful web service at the URL shown, retrieves a random joke in JavaScript Object Notation (JSON) form, parses (or, rather, slurps) it, and prints the resulting joke. The script uses the safe dereference operator to avoid NullPointerExceptions in case something goes wrong, but it has an assert statement to check that something actually was retrieved. When executed, the result is something like

Chuck Norris can instantiate an interface

6 Arguably, this is why the internet was invented.

www.it-ebooks.info

138

CHAPTER 6 Testing Groovy and Java projects

To test this script all I need to do is execute it and let the embedded assert statement do the work. I can execute it programmatically as in the following listing.

Listing 6.7 A class to hold all the script tests

class ScriptTests { @Test

void testChuckNorrisScript() { GroovyShell shell = new GroovyShell()

shell.evaluate(new File('src/main/groovy/mjg/chuck_norris.groovy'))

}

}

The GroovyShell class, discussed in chapter 3 on Groovy and Java integration, has an evaluate method that takes a File argument. I simply point the File to the script in question, and the evaluate method on the shell executes it.

What if I want to check the results? In this case the result is random, but if my script has an actual result based on input values, is there something that can be done then?

To handle this I’m going to need a binding for the script (again discussed in chapter 3). A binding is an object that allows input and output variables to be accessed from the script.

SCRIPT BINDING Any variable that isn’t declared in a script is part of the binding and can be accessed from outside.

Consider the classic “Hello, World!” script in Groovy. I’ll put it in a package in the next listing, but other than that it’s the same script described in appendix B, “Groovy by Feature.”

Listing 6.8 The “Hello, World!” script

package mjg

println 'Hello, World!'

This script doesn’t contain any assert statements, but because it prints to the console I’d like to be able to check the output. To do so I can assign the out property of the corresponding binding to a StringBuffer, which I can access after the script executes.7 The following test has been added to the ScriptTests class started in listing 6.7.

Listing 6.9 A test that captures script output

@Test

void testHelloWorld() {

Binding binding = new Binding()

7This isn’t documented well at all, so consider it more value added for you by reading this book. Guillaume Laforge told me about it (and wrote it, too), so he gets the real credit.

www.it-ebooks.info

Testing scripts written in Groovy

139

def content = new StringWriter() binding.out = new PrintWriter(content)

GroovyShell shell = new GroovyShell(binding)

shell.evaluate(new File('src/main/groovy/mjg/hello_world.groovy')) assert "Hello, World!" == content.toString().trim()

}

The out property of the binding is assigned to a PrintWriter wrapped around a StringWriter, so that when the println method in the script is executed, the output goes to the writer instead of the console. Then, after executing the script using the shell, I can check that the proper statement was printed by accessing the writer and trimming its output.

Normally a binding is used to pass input variables into a script. Here’s a slight variation on the previous example, using a name variable.

Listing 6.10 A script with a binding variable

package mjg

println "Hello, $name!"

Again, the only real difference here is that the print statement uses a name variable that is not declared inside the script. That means it can be passed in from outside, as shown in the following test.

Listing 6.11 Setting a binding variable to test a script

@Test

void testHelloName() {

Binding binding = new Binding() binding.name = 'Dolly'

def content = new StringWriter() binding.out = new PrintWriter(content)

GroovyShell shell = new GroovyShell(binding)

shell.evaluate(new File('src/main/groovy/mjg/hello_name.groovy')) assert "Hello, Dolly!" == content.toString().trim()

}

The name variable is set to Dolly, and the result is confirmed as before.

6.2.1Useful subclasses of GroovyTestCase: GroovyShellTestCase

The combination of script and binding is sufficiently common that the Groovy API now includes the class groovy.util.GroovyShellTestCase. This is a subclass of GroovyTestCase that instantiates a GroovyShell inside the setUp method. The shell is provided as a protected attribute, but the class also includes a withBinding method that takes a Map of parameters and a closure to execute. The following listing shows tests for the Groovy scripts in this section.

www.it-ebooks.info

Adding an input parameter
Changing the out variable in the binding

140

CHAPTER 6 Testing Groovy and Java projects

 

 

 

 

Listing 6.12 Testing Groovy scripts using GroovyShellTestCase

 

class ScriptShellTests extends GroovyShellTestCase {

Executing a script,

 

String base = 'src/main/groovy'

which includes

 

 

assert statements

void testChuckNorris() {

shell.evaluate(new File("$base/mjg/chuck_norris.groovy"))

}

void testHelloWorld() {

def content = new StringWriter()

withBinding([out:new PrintWriter(content)]) { shell.evaluate(new File("$base/mjg/hello_world.groovy")) assert "Hello, World!" == content.toString().trim()

}

}

void testHelloName() {

def content = new StringWriter()

withBinding([out:new PrintWriter(content), name:'Dolly']) { shell.evaluate(new File("$base/mjg/hello_name.groovy")) assert "Hello, Dolly!" == content.toString().trim()

}

}

}

The first test finds the script to run and executes it using the shell instantiated in the superclass. The other tests use the withBinding method to override the out variable and provide an input parameter. The results are the same as instantiating the GroovyShell and Binding classes directly.

The previous example showed how to capture standard output from a script, but normally scripts return concrete values. The withBinding method returns whatever the script returns. As a trivial example, consider the following powerful Groovy calculator, saved in a file called calc.groovy:

z = x + y

Because none of the three variables (x, y, and z) are declared, they can all be accessed through the script’s binding. The next listing shows a test for this script that validates the returned value.

Listing 6.13 A test for the addition script, calc.groovy

void testAddition() {

def result = withBinding( [x:3,y:4] ) {

shell.evaluate(new File('src/main/groovy/mjg/calc.groovy')) shell.context.z

}

assert 7 == result

}

The last line of the closure accesses the z variable, whose value is retrieved from the binding.

www.it-ebooks.info

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]