- •brief contents
- •contents
- •foreword
- •preface
- •acknowledgments
- •about this book
- •Roadmap
- •Code conventions and downloads
- •Author Online
- •About the author
- •about the cover illustration
- •1 Why add Groovy to Java?
- •1.1 Issues with Java
- •1.1.1 Is static typing a bug or a feature?
- •1.1.2 Methods must be in a class, even if you don’t need or want one
- •1.1.3 Java is overly verbose
- •1.1.4 Groovy makes testing Java much easier
- •1.1.5 Groovy tools simplify your build
- •1.2 Groovy features that help Java
- •1.3 Java use cases and how Groovy helps
- •1.3.1 Spring framework support for Groovy
- •1.3.2 Simplified database access
- •1.3.3 Building and accessing web services
- •1.3.4 Web application enhancements
- •1.4 Summary
- •2 Groovy by example
- •2.1 Hello, Groovy
- •2.2 Accessing Google Chart Tools
- •2.2.1 Assembling the URL with query string
- •2.2.2 Transmitting the URL
- •2.2.3 Creating a UI with SwingBuilder
- •2.3 Groovy Baseball
- •2.3.1 Database data and Plain Old Groovy Objects
- •2.3.2 Parsing XML
- •2.3.3 HTML builders and groovlets
- •2.4 Summary
- •3 Code-level integration
- •3.1 Integrating Java with other languages
- •3.2 Executing Groovy scripts from Java
- •3.2.1 Using JSR223 scripting for the Java Platform API
- •3.2.2 Working with the Groovy Eval class
- •3.2.3 Working with the GroovyShell class
- •3.2.4 Calling Groovy from Java the easy way
- •3.2.5 Calling Java from Groovy
- •3.3 Summary
- •4 Using Groovy features in Java
- •4.1 Treating POJOs like POGOs
- •4.2 Implementing operator overloading in Java
- •4.3 Making Java library classes better: the Groovy JDK
- •4.4 Cool AST transformations
- •4.4.1 Delegating to contained objects
- •4.4.2 Creating immutable objects
- •4.4.3 Creating singletons
- •4.5 Working with XML
- •4.6 Working with JSON data
- •4.7 Summary
- •5 Build processes
- •5.1 The build challenge
- •5.2 The Java approach, part 1: Ant
- •5.3 Making Ant Groovy
- •5.3.1 The <groovy> Ant task
- •5.3.2 The <groovyc> Ant task
- •5.3.3 Writing your build in Groovy with AntBuilder
- •5.3.4 Custom build scripts with Gant
- •5.3.5 Ant summary
- •5.4 The Java approach, part 2: Maven
- •5.4.2 The GMaven project
- •5.4.3 Maven summary
- •5.5 Grapes and @Grab
- •5.6 The Gradle build system
- •5.6.1 Basic Gradle builds
- •5.6.2 Interesting configurations
- •5.7 Summary
- •6 Testing Groovy and Java projects
- •6.1 Working with JUnit
- •6.1.1 A Java test for the Groovy implementation
- •6.1.2 A Groovy test for the Java implementation
- •6.1.3 A GroovyTestCase test for a Java implementation
- •6.2 Testing scripts written in Groovy
- •6.2.1 Useful subclasses of GroovyTestCase: GroovyShellTestCase
- •6.2.2 Useful subclasses of GroovyTestCase: GroovyLogTestCase
- •6.3 Testing classes in isolation
- •6.3.1 Coerced closures
- •6.3.2 The Expando class
- •6.3.3 StubFor and MockFor
- •6.4 The future of testing: Spock
- •6.4.1 The Search for Spock
- •6.4.2 Test well, and prosper
- •6.4.4 The trouble with tribbles
- •6.4.5 Other Spock capabilities
- •6.5 Summary
- •7 The Spring framework
- •7.1 A Spring application
- •7.2 Refreshable beans
- •7.3 Spring AOP with Groovy beans
- •7.4 Inline scripted beans
- •7.5 Groovy with JavaConfig
- •7.6 Building beans with the Grails BeanBuilder
- •7.7 Summary
- •8 Database access
- •8.1 The Java approach, part 1: JDBC
- •8.2 The Groovy approach, part 1: groovy.sql.Sql
- •8.3 The Java approach, part 2: Hibernate and JPA
- •8.4 The Groovy approach, part 2: Groovy and GORM
- •8.4.1 Groovy simplifications
- •8.5 Groovy and NoSQL databases
- •8.5.1 Populating Groovy vampires
- •8.5.2 Querying and mapping MongoDB data
- •8.6 Summary
- •9 RESTful web services
- •9.1 The REST architecture
- •9.3 Implementing JAX-RS with Groovy
- •9.4 RESTful Clients
- •9.5 Hypermedia
- •9.5.1 A simple example: Rotten Tomatoes
- •9.5.2 Adding transitional links
- •9.5.3 Adding structural links
- •9.5.4 Using a JsonBuilder to control the output
- •9.6 Other Groovy approaches
- •9.6.1 Groovlets
- •9.6.2 Ratpack
- •9.6.3 Grails and REST
- •9.7 Summary
- •10 Building and testing web applications
- •10.1 Groovy servlets and ServletCategory
- •10.2 Easy server-side development with groovlets
- •10.2.1 A “Hello, World!” groovlet
- •10.2.2 Implicit variables in groovlets
- •10.3.2 Integration testing with Gradle
- •10.3.3 Automating Jetty in the Gradle build
- •10.4 Grails: the Groovy “killer app”
- •10.4.1 The quest for the holy Grails
- •10.5 Summary
- •A.1 Installing a JDK
- •A.2 Installing Groovy
- •A.3 Testing your installation
- •A.4 IDE support
- •A.5 Installing other projects in the Groovy ecosystem
- •B.1 Scripts and the traditional example
- •B.2 Variables, numbers, and strings
- •B.2.1 Numbers
- •B.2.2 Strings and Groovy strings
- •B.3 Plain Old Groovy Objects
- •B.4 Collections
- •B.4.1 Ranges
- •B.4.2 Lists
- •B.4.3 Maps
- •B.5 Closures
- •B.6 Loops and conditionals
- •B.6.1 Loops
- •B.6.2 Conditionals
- •B.6.3 Elvis
- •B.6.4 Safe de-reference
- •B.7 File I/O
- •B.8.1 Parsing and slurping XML
- •B.8.2 Generating XML
- •B.8.3 Validation
- •B.9 JSON support
- •B.9.1 Slurping JSON
- •B.9.2 Building JSON
- •index
- •Symbols
The future of testing: Spock |
161 |
What if the class you plan to test has dependencies? Those dependencies need to be stubbed or mocked, as discussed earlier. Fortunately, Spock has its own mocking capabilities built in.
6.4.4The trouble with tribbles
The Specification class from Spock contains a method called Mock that is used to create mock objects. If your dependency is based on an interface, the Mock method can generate a mock object directly, using Java’s dynamic proxy mechanism. If it’s a class, Mock will extend the class using the CGLIB library.
It’s time for a relatively simple (and relatively silly) example. A tribble22 is a small, furry animal that breeds prolifically, likes Vulcans, and hates Klingons. Here’s a Tribble class, written in Groovy.
Listing 6.29 A Tribble class in Groovy
class Tribble {
String react(Vulcan vulcan) { vulcan.soothe()
"purr, purr"
}
String react(Klingon klingon) { klingon.annoy()
"wheep! wheep!"
}
def feed() {
def tribbles = [this]
10.times { tribbles << new Tribble() } return tribbles
}
}
What do you get when you feed a tribble? Not a fat tribble, but rather a lot of hungry little tribbles. The feed method returns a list containing the original tribble plus 10 more.
The overloaded react method takes either a Vulcan or a Klingon as an argument. If it’s a Vulcan, the tribble soothes the Vulcan and purrs contentedly. If it’s a Klingon, the tribble annoys the Klingon and reacts badly. The Tribble class has a dependency on both Vulcan and Klingon.
To keep things simple, both Vulcan and Klingon are interfaces. The Vulcan interface is shown here:
interface Vulcan { def soothe()
def decideIfLogical()
}
22See http://en.wikipedia.org/wiki/The_Trouble_With_Tribbles for details, in the unlikely event you haven’t seen that particular Star Trek (original series) episode. It holds up remarkably well after 35 (!) years.
www.it-ebooks.info
162 |
CHAPTER 6 Testing Groovy and Java projects |
Vulcans have a soothe method, called by the tribble, and a decideIfLogical method that isn’t necessary for this test. That’s one of the problems with implementing stubs, by the way; you have to implement all the interface methods, even the ones that aren’t relevant to the test in question.
Klingons are a bit different:
interface Klingon { def annoy()
def fight()
def howlAtDeath()
}
Tribbles annoy Klingons. Klingons also fight and howlAtDeath,23 two methods that aren’t needed here. To test the Tribble class, I need to create mock objects for both the Vulcan and Klingon classes, set their expectations appropriately, and test that the tribble behaves appropriately around each.
Let me show the tests one by one. First I’ll check to see that the feed method works properly:
def "feed a tribble, get more tribbles"() { when:
def result = tribble.feed()
then:
result.size() == 11 result.every {
it instanceof Tribble
}
}
The when block invokes the feed method. The then block checks that there are 11 elements in the returned collection and that each is a tribble. There’s nothing new or unusual about this test. Moving on to the test for reacting to Vulcans, however, I need to mock the Vulcan interface.24
def "reacts well to Vulcans"() { Vulcan spock = Mock()
when:
String reaction = tribble.react(spock)
then:
reaction == "purr, purr" 1*spock.soothe()
}
There are two ways to use the Mock method in Spock. The first is shown here: instantiate the class, and assign it to a variable of the proper type. The method will implement
23Klingons in Star Trek: The Next Generation howl at death. They didn’t in the original series, as far as I know.
24When I mock a Vulcan, I feel like Dr. McCoy.
www.it-ebooks.info
The future of testing: Spock |
163 |
the interface of the declared type. The second way is to use the interface type as an argument to the Mock method, which isn’t shown here.
Once the mock has been created, the when block uses the mock as the argument to the react method. In the then block, first the proper reaction is checked, and then comes the interesting part. The last line says that the test passes only if the soothe method is called on the mock exactly one time, ignoring any returned value.
This is a very flexible system. The cardinality can be anything, including using an underscore as a wild card (for example, (3.._) means three or more times).
Moving on to the Klingon interface, the following test does multiple checks:
def "reacts badly to Klingons"() { Klingon koloth = Mock()
when:
String reaction = tribble.react(koloth)
then:
1 * koloth.annoy() >> { throw new Exception()
}
0 * koloth.howlAtDeath() reaction == null Exception e = thrown()
}
After mocking the Klingon25 and invoking the react method, the then block first checks to see that the annoy method on the mock is invoked exactly once and, using the right-shift operator, implements the method by throwing an exception. The next line checks that the howlAtDeath method is not invoked at all. Because the annoy method throws an exception, there is no returned reaction. The last line then verifies that annoying the Klingon did in fact throw the expected exception.
The idea is that even if the mock is configured to throw an exception, the tribble test still passes. The test verifies that the exception is thrown without making the test itself fail.
6.4.5Other Spock capabilities
The capabilities shown so far hopefully provide a teaser for Spock. There are more features in Spock that go beyond the scope of this chapter. For example, the @Ignore annotation on a test skips that test, but there’s also an @IgnoreRest annotation that skips all the other tests instead. The @IgnoreIf annotation checks a Boolean condition and skips the test if the condition evaluates to true. There’s also a @Stepwise annotation for tests that have to be executed in a particular order, and a @Timeout annotation for tests that are taking too long to execute.
25 How do you mock a Klingon? From a galaxy far, far away (rimshot).
www.it-ebooks.info