2. Joseph Muraski Independent Consultant in the Twin Cities Develop enterprise applications using Java, .Net, Groovy, Grails… Email: joe.muraski@mantacs.com Twitter: jmuraski Blog: joemuraski.blogspot.com
3. Christopher Bartling Independent consultant, based in the Twin Cities Teach, mentor and coach for DevJam Experiences include building enterprise applications with Java, Groovy, Grails, .NET, and Adobe Flex Email: chris.bartling@gmail.com Twitter: cbartling Blog: bartling.blogspot.com
4. Goals of the workshop Introduce features in Groovy that will help your Java testing efforts Introduce Cucumber and cuke4duke as new tools in your testing arsenal Demonstrate unit, integration, and acceptance testing with Groovy and Cucumber (via cuke4duke) via an example Java web application Get hands on with these technologies
5. Summary Design principles Testing facilities built into Groovy Acceptance/BDD testing with Groovy Cucumber and cuke4duke Presentation and code available http://bitbucket.org/joe.muraski/grails_tdd_workshop/ Instructions on how to use Mercurial to clone the repository or retrieve everything in an archive file
6. Prerequisites for hands on labs Java 1.6 JDK installation Maven 2 That’s it…Maven will take care of resolving all the other dependencies
7. Maven 2 Maven2 installation required We’re using version 2.2.1 This is not a Maven presentation We use it because it’s quite handy and does a great job of resolving dependencies Maven commands will be presented when needed
8. Maven plugins used org.codehaus.gmaven:gmaven-plugin:1.2 org.mortbay.jetty:maven-jetty-plugin cuke4duke:cuke4duke-maven-plugin:0.2.4 org.apache.maven.plugins:maven-surefire-plugin
9. Sample web application Starting the web app mvn jetty:run-exploded Running tests mvn tests Running cuke4duke mvn cuke4duke:cucumber
10. Design principles Single responsibility per class (high cohesion) Loose coupling of collaborators (low coupling) Injection of dependencies
11. Why Groovy? Groovy works seamlessly with Java It’s all just bytecode in the end Groovy offers a relaxed Java syntax Interesting tools included in Groovy GSQL XmlSlurper, XmlParser, Builders GPath Convenient collections Private method testing
12. GroovyTestCase Included in Groovy distribution Extends junit.framework.TestCase Provides a number of helper methods for assertions Does not require test* methods to be void return type No need to declared throws checked exceptions in tests Groovy converts checked exceptions to unchecked exceptions
14. shouldFail() closures shouldFail(Closure closure) Asserts supplied closure fails when evaluated shouldFail(Class desiredThrownType, Closure closure) Asserts supplied closure fails when evaluated and particular exception type is thrown shouldFailWithCause(Class desiredCauseType, Closure closure) Will check for a checked exception as the root cause (checked exceptions are wrapped in Groovy)
16. Map coercion Add named closures to the map Only one closure can be mapped to a “method name” Cannot overload methods Coerce to desire type using the as operator
18. Private Method Calling Groovy can call private methods Broken encapsulation? Better reflection abstractions? Java can invoke private methods, it’s just more painful Is testing private methods Good or a Smell?
20. Groovy mocking library Groovy's built-in mock support does not allow us to test Java classes Relies on hooking into Groovy's object lifecycle mechanisms Java can not make call to Groovy Mock or Stub Use Java mocking frameworks instead Can cheat by putting Groovy Mock in a coerced map but why??
21. GMock Groovy-based mock objects framework Easy syntax and usage Works when called by Java classes
24. Java Mocking Frameworks Java Mocking frameworks can be used with Groovy Some have minor syntax issues or needed work arounds (JMock) Great to use if you already have one you are using and don’t want to switch
25. GSQL Easy to create connections sql= Sql.newInstance("jdbc:hsqldb:hsql://localhost/", "sa", "", "org.hsqldb.jdbcDriver") Simple to work with row sets sql.rows(“select * from address”).each {println “id: ${it.id}”} No try catch blocks
27. Acceptance Test-Driven Story tests manifest themselves as executable tests Drives the development of complete features Frameworks are available Fit, FitLibrary, FitNesse http://fit.c2.com/ Robot Framework http://code.google.com/p/robotframework/ Cucumber http://cukes.info/ Others
28. Cucumber Tool for executing plain-text functional descriptions as automated tests Supports BDD Cucumber tests are typically written before anything else verified by business analysts, domain experts, non-technical stakeholders The production code is then written to make the Cucumber tests pass Outside-in development
29. Cucumber (via cuke4duke) Cucumber for the JVM Outside-in testing Facilitates automation of acceptance/story tests Features and scenarios use normal language Step definitions can be written in Groovy, as we’ll see Uses JRuby to run the core Cucumber framework http://wiki.github.com/aslakhellesoy/cuke4duke/
30. Cucumber features Purposes Documentation of the system Automated, executable acceptance tests What code should I write next? Written in Gherkin Business readable DSL Describe software behavior without detailing implementation Grammar exists in different spoken languages (37 currently) Feature source files have .feature extension
31. Given-When-Then Scenarios consist of steps Given: Put the system in a known state before the user starts interacting with the system; pre-conditions When: Describe the key action a user performs in this scenario Then: Observe outcomes; observations should relate to business value of the feature Use And and But to keep features fluent
32. Cucumber step definitions Written in Groovy for our examples Can be written in many different programming languages Analogous to method or function definition Start with adjective/adverb Regular expression which will match some text from a feature(s) Take 0 or more arguments Arguments bound to regular expression groups Multi-line step arguments
33. Hooks Before Executes before the first step of each scenario After Executes after the last step of each scenario Execute regardless if there are failing, undefined, pending or skipped steps AfterStep Executes after each step in a scenario
34. Hooks Found in Groovy files in the support directory Our example uses one: env.groovy Hooks allow us to run blocks of code at various points in the Cucumber test cycle No association between where the hook is defined and which scenario/step it is run for All defined hooks (one or more) are run whenever the relevant event occurs
35. Tagged hooks Need to execute a certain hook for only certain scenarios Achieved by associating a Before, After or AfterStep hook with one or more tags See the env.groovy file It uses a Before hook with a @database tag to load the database via DBUnit
36. Tagging scenarios Allows you to group scenarios for inclusion or exclusion in a Cucumber run @wip is provided out of the box Using tags in cuke4duke and Maven… mvn cuke4duke:cucumber –DcukeArgs=“--tags @wip” mvn cuke4duke:cucumber -DcukeArgs=“--tags ~@wip” Inside of the Maven POM: <cucumberArg>${cukeArgs}</cucumberArg>
37. Running cuke4duke The cuke4duke Maven plugin mvn cuke4duke:cucumber First time: use –Dcucumber.installGems=true Add –o option to work offline Features and step definitions are discovered by the plugin Features belong in features directory Step definitions found in the step_definitions directory
38. cuke4duke acceptance tests Step definitions will be written in Groovy Other JVM languages are allowed Use cuke4duke.GroovyDsl Use WebDriver: http://code.google.com/p/selenium Test web UI Use DbUnit: http://www.dbunit.org/ Bulk load the database with known fixture data
41. Workshop activities Now it’s your turn! Try your hand at unit testing with Groovy Refactor the existing web app Introduce DAO for database functionality Add services to orchestrate business logic Write some Cucumber features and build out or reuse the Groovy step definitions Try to add new features and practice outside-in development Is ATDD beneficial? Why or why not?
Behaviour-driven development is an “outside-in” methodology. It starts at the outside by identifying business outcomes, and then drills down into the feature set that will achieve those outcomes. Each feature is captured as a “story”, which defines the scope of the feature along with its acceptance criteria. This article introduces the BDD approach to defining and identifying stories and their acceptance criteria.