SlideShare ist ein Scribd-Unternehmen logo
1 von 79
Downloaden Sie, um offline zu lesen
Industrial
Strength Groovy
Tools for the Professional Groovy Developer
Dr Paul King, ASERT: @paulk_asert
Topics

• Testing/Mocking: JUnit, TestNG, EasyB, Spock,
  Instinct, MockFor, Gmock, EasyMock
• Injection: Spring, Guice
• Coverage: Cobertura
• Code style: CodeNarc, IntelliJ
• Duplication: Simian
• Documentation: GroovyDoc
• Builds: Ant, Gant, GMaven, Gradle, Hudson
• Modularisation: Grapes, OSGi
INTRO
©   What is Groovy?
A
S
E
R
T

2
0
0
6
-
2
0   • ―Groovy is like a super version
0
9     of Java. It can leverage Java's
      enterprise capabilities but also
      has cool productivity features like closures,
      DSL support, builders and dynamic typing.‖



                       SpringOne2gx_Oct2009 - 4
©   Groovy Goodies Overview
A
S
E

    • Fully object oriented
R
T

2
0
    • Closures: reusable                 • GPath: efficient
0
6
      and assignable pieces                object navigation
-
2
      of code                            • GroovyBeans
    • Operators can be
0
0                                        • grep and switch
      overloaded
9
                                         • Templates, builder,
    • Multimethods                         swing, Ant, markup,
    • Literal declaration for              XML, SQL, XML-RPC,
      lists (arrays), maps,                Scriptom, Grails,
      ranges and regular                   tests, Mocks
      expressions

                          SpringOne2gx_Oct2009 - 5
Growing Acceptance …


                         Making
                         Java
                         Groovy
                         (soon)




Now free
©
    … Growing Acceptance …
A
S
E
R
T

2
0
0
6
-
2
0
0
9

                 http://www.jroller.com/scolebourne/entry/devoxx_2008_whitebo




                      SpringOne2gx_Oct2009 - 7
                                                 http://www.java.net
©   … Growing Acceptance …
What alternative JVM language are you using or intending to use
A
S
E
R
T

2
0
0
6
-
2
0
0
9




                  http://www.leonardoborges.com/writings
                               SpringOne2gx_Oct2009 - 8
©   … Growing Acceptance …
A
S
E
R
T

2
0
0
6
-
2
0
0
9




     http://it-republik.de/jaxenter/quickvote/results/1/poll/44 (translated using http://babelfish.yahoo
                                          SpringOne2gx_Oct2009 - 9
©   … Growing Acceptance
A
S
E
R
T

2
0
0
6
-
2
0
0
9




                   SpringOne2gx_Oct2009 - 10
Groovy‘s Appeal

• Innovators/Thought leaders
  – Ideas, power, flexibility, novelty, thinking community
• Early adopters
  – Productivity benefits and collegiate community
  – Leverage JVM and potential for mainstream
• Mainstream
  –   Leverage existing Java skills, low learning curve
  –   Leverage JVM and production infrastructure
  –   Professional community
  –   Tools, tools, tools
TESTING


      SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Utilities              Runners
Groovy and Testing Tool Spectrum
                                   AllPairs,
                                   Combinations           Native Groovy, JUnit, TestNG, Spock, EasyB,
                                   Polyglot languages     JBehave, Cucumber, Robot Framework
                                   Logic programming
                                   Threads, Parallel /
                                   Concurrency            Web           Database     SOAP /    Other
                                   libraries              Drivers       Drivers      REST      Drivers
                                   Data-driven                                       Drivers
                                                          WebTest       DbUnit                FEST
                                   libraries
                                                          WebDriver     DataSets     GroovyWS Email
                                   Networking libraries
                                   XML Processing         JWebUnit      SqlUnit      XML-RPC  FTP
                                   Read/write files /     Tellurium     groovy.sql   CXF      AntUnit
                                   Excel / Word / CSV     Selenium      JPA          Axis2    Telnet
                                   Reporting, Logging     HtmlUnit      JDO          JAX-WS   SSH
                                                          Watij         BigTable     JAX-RS   Exec
                                   Tools
                                                          HttpBuilder   JDBC
                                   iTest2, SoapUI,
                                   Twist, IDEs, JMeter,
                                                          Cyberneko
                                   Text editors,
                                   Recorders, Sahi,
                                   Build Tools, CI
Testing: JUnit

  import org.junit.Test
  import static org.junit.Assert.assertEquals

  class ArithmeticTest {
      @Test
      void additionIsWorking() {
          assertEquals 4, 2+2
      }

      @Test(expected=ArithmeticException)
      void divideByZero() {
          println 1/0
      }
  }
Testing: TestNG

   import ...
   public class SimpleTest {

       @BeforeClass
       public void setUp() {
         // code invoked when test is created
       }

       @Test(groups = [ "fast" ])
       public void aFastTest() {
         System.out.println("Fast test");
       }

       @Test(groups = [ "slow" ])
       public void aSlowTest() {
          System.out.println("Slow test");
       }
   }
import static org.easymock.EasyMock.*
                    mockControl = createStrictControl()
                    mockReverser = mockControl.createMock(Reverser)
                    storer = new JavaStorer(mockReverser)
                    testStorage()
                    def testStorage() {
                       expectReverse(123.456, -123.456)
Mocking: EasyMock




                       expectReverse('hello', 'olleh')
                       mockControl.replay()
                       checkReverse(123.456, -123.456)
                       checkReverse('hello', 'olleh')
                       mockControl.verify()
                    }
                    def expectReverse(input, output) {
                       expect(mockReverser.reverse(input)).andReturn(output)
                    }
                    def checkReverse(value, reverseValue) {
                       storer.put(value)
                       assert value == storer.get()
                       assert reverseValue == storer.getReverse()
                    }
class a_default_storer {
                        def storer
                        @initially void create_new_storer() {
                            storer = new Storer()
                        }
                        private check_persist_and_reverse(value, expectedReverse) {
                            storer.put(value)
                            def persisted = storer.get()
                            assert persisted == value
                            def reversed = storer.reverse
                            assert reversed == expectedReverse
Testing: Instinct




                        }
                        @spec def should_reverse_numbers() {
                            check_persist_and_reverse 123.456, -123.456
                        }
                        @spec def should_reverse_strings() {
                            check_persist_and_reverse 'hello', 'olleh'
                        }
                        @spec def should_reverse_lists() {
                            check_persist_and_reverse([1, 3, 5], [5, 3, 1])
                        }
                    }

                    check_specs_for a_default_storer
import groovy.mock.interceptor.MockFor

                   def mocker = new MockFor(Collaborator.class)    //   create the Mock support
                   mocker.demand.one(1..2) { 1 }                   //   demand the 'one' method one
                                                                   //   or two times, returning 1
                   mocker.demand.two()      { 2 }                  //   demand the 'two' method
                                                                   //   exactly once, returning 2
                   mocker.use {                                    //   start using the Mock
                       def caller =   new Caller()                 //   caller will call Collaborator
                       assertEquals   1, caller.collaborateOne()   //   will call Collaborator.one
                       assertEquals   1, caller.collaborateOne()   //   will call Collaborator.one
                       assertEquals   2, caller.collaborateTwo()   //   will call Collaborator.two
Mocking: MockFor




                   }                                               //   implicit verify here


                           import groovy.mock.interceptor.MockFor

                           def mocker = new MockFor(Collaborator.class)
                           mocker.demand.one(1..2) { 1 }
                           mocker.demand.two()     { 2 }
                           mocker.use {
                               def caller = new Caller()
                               assertEquals 1, caller.collaborateOne()
                               assertEquals 1, caller.collaborateOne()
                               assertEquals 2, caller.collaborateTwo()
                           }
Mocking: Gmock ...

•   Method mocking: mockLoader.load("fruit").returns("apple")

•   Exception mocking: mockLoader.load("unknown").raises(new RuntimeException())

•   Stub mocking: mockLoader.load("fruit").returns("apple").stub()

•   Static method mocking: mockMath.static.random().returns(0.5)

•   Property mocking: mockLoader.name.returns("loader")

•   Constructor mocking: def mockFile = mock(File, constructor('/a/path/file.txt'))

•   Partial mocking: mock(controller).params.returns([id: 3])

•   Times expectation: mockLoader.load("fruit").returns("apple").atLeastOnce()

•   Custom matcher: mockLoader.load(match{ it.startsWith("fru") })

•   Strict ordering: ordered { ... }

•   Optional support for Hamcrest matcher: mockLoader.put("test", is(not(lessThan(5))))

•   GMockController if you can't extend GMockTestCase in your test
Mocking: Gmock


 import org.gmock.GMockTestCase

 class LoaderTest extends GMockTestCase {
     void testLoader(){
         def mockLoader = mock()
         mockLoader.load('key').returns('value')
         play {
             assertEquals "value", mockLoader.load('key')
         }
     }
 }
Testing: Spock ...
... Testing: Spock

  @Speck
  @RunWith(Sputnik)
  class PublisherSubscriberSpeck {
    def "events are received by all subscribers"() {
      def pub = new Publisher()
      def sub1 = Mock(Subscriber)
      def sub2 = Mock(Subscriber)
      pub.subscribers << sub1 << sub2

          when:
          pub.send("event")

          then:
          1 * sub1.receive("event")
          1 * sub2.receive("event")
      }
  }
Testing: EasyB ...


given "an invalid zip code", {
    invalidzipcode = "221o1"
}

and "given the zipcodevalidator is initialized", {
    zipvalidate = new ZipCodeValidator()
}

when "validate is invoked with the invalid zip code", {
    value = zipvalidate.validate(invalidzipcode)
}

then "the validator instance should return false", {
    value.shouldBe false
}
before "start selenium", {
                       given "selenium is up and running", {
                         // start selenium
                       }
                     }

                     scenario "a valid person has been entered", {

                         when "filling out the person form with a first and last name", {
                           selenium.open("http://acme.racing.net/greport/personracereport.html")
                           selenium.type("fname", "Britney")
                           selenium.type("lname", "Smith")
                         }
Testing: EasyB ...




                         and "the submit link has been clicked", {
                           selenium.click("submit")
                         }

                         then "the report should have a list of races for that person", {
                           selenium.waitForPageToLoad("5000")
                           values = ["Mclean 1/2 Marathon", "Reston 5K", "Herndon 10K", "Leesburg 10K"]
                           for(i in 0..<values.size()){
                             selenium.getText("//table//tr[${(i+3)}]/td").shouldBeEqualTo values[i]
                           }
                         }
                     }

                     after "stop selenium" , {
                       then "selenium should be shutdown", {
                         // stop selenium
                       }
                     }
Dependency Injection

• Hollywood Principle
  – Don‘t call us, we‘ll call you
• “All problems in computer science
  can be solved by another level of
  indirection”
• "...except for the problem of too
  many layers of indirection“
  – For attributions, see
    http://en.wikipedia.org/wiki/Inversion_of_control
Dependency Injection

• Pattern for loosely coupled & testable objects

      class Client {              class Client {
        Calculator calc =           Calculator calc
          new CalculatorImpl()      def executeCalc(a, b) {
        def executeCalc(a, b) {       calc.add(a, b)
          calc.add(a, b)            }
        }                         }
      }

     Service locator/factory        Need to select setter,
                                      constructor, field style
     Tightly coupled?
                                     Can add complexity
     Hard to test?
                                     Manage configuration
     Easy to understand?
                                     Direct or framework
     Refactoring/navigation?
                                     Consistency/lifecycle
Dependency Injection: Spring ...

• Several flavors
   – let‘s look at Annotation and BeanBuilder flavors
    import org.springframework.stereotype.Component

    @Component class AdderImpl {
        def add(x, y) { x + y }
    }

    import org.springframework.beans.factory.annotation.Autowired
    import org.springframework.stereotype.Component

    @Component class CalcImpl3 {
        @Autowired private AdderImpl adder
        def doAdd(x, y) { adder.add(x, y) }
    }
... Dependency Injection: Spring

import org.springframework.context.support.GenericApplicationContext
import
org.springframework.context.annotation.ClassPathBeanDefinitionScanner

def ctx = new GenericApplicationContext()
new ClassPathBeanDefinitionScanner(ctx).scan('')
ctx.refresh()
def calc = ctx.getBean('calcImpl3')
println calc.doAdd(3, 4) // => 7

    def bb = new grails.spring.BeanBuilder()
    bb.beans {
        adder(AdderImpl)
        calcBean(CalcImpl2) { delegate.adder = adder }
    }
    def ctx = bb.createApplicationContext()
    def calc = ctx.getBean('calcBean')
    println calc.doAdd(3, 4) // => 7
Dependency Injection: Guice
                              import com.google.inject.*

                              @ImplementedBy(CalculatorImpl)
                              interface Calculator {
                                  def add(a, b)
                              }

                              @Singleton
                              class CalculatorImpl implements Calculator {
                                  private total = 0
                                  def add(a, b) { total++; a + b }
                                  def getTotalCalculations() { 'Total Calculations: ' + total }
                                  String toString() { 'Calc: ' + hashCode()}
                              }

                              class Client {
                                  @Inject Calculator calc
                                  // ...
                              }

                              def injector = Guice.createInjector()
                              // ...
Dependency Injection:
Metaprogramming Style

   class Calculator {
       def total = 0
       def add(a, b) { total++; a + b }
   }

   def INSTANCE = new Calculator()
   Calculator.metaClass.constructor = { -> INSTANCE }

   def c1 = new Calculator()
   def c2 = new Calculator()

   assert c1.add(1, 2) == 3
   assert c2.add(3, 4) == 7

   assert c1.is(c2)
   assert [c1, c2].total == [2, 2]
CODE QUALITY
Coverage: Cobertura ...

                      Ant
...Coverage: Cobertura ...


                                                                              Maven




                             cobertura-instrument
                             java –cp ...                               Command-line
                             cobertura-report
                             cobertura-check
                             cobertura-merge

                                                                               Grails
                             grails install-plugin code-coverage --global
...Coverage: Cobertura
Remember 100% coverage rule ...   • Necessary but not sufficient condition




                                                                             // 100%
...Remember 100% coverage rule ...   • Necessary but not sufficient condition




                                                                                // 100%

                                                                                // Fail
...Remember 100% coverage rule   • Necessary but not sufficient condition
Code style: CodeNarc ...




                  About 50 rules (1 broken?)
... Code style: CodeNarc ...
... Code style: CodeNarc
Code style: IntelliJ
Duplication: Simian ...

Simian fully supports the following languages:
• Java
• C#
• C++
                                    with partial support
• C
                                     for:
• Objective-C
• JavaScript (ECMAScript)           •   JSP
• COBOL, ABAP                       •   ASP
• Ruby                              •   HTML
• Lisp                              •   XML
• SQL
• Visual Basic
• Groovy
... Duplication: Simian ...
... Duplication: Simian ...
... Duplication: Simian

Similarity Analyser 2.2.23 -
     http://www.redhillconsulting.com.au/products/simian/index.html
Copyright (c) 2003-08 RedHill Consulting Pty. Ltd. All rights reserved.
Simian is not free unless used solely for non-commercial or evaluation
     purposes.
{failOnDuplication=true, ignoreCharacterCase=true,
     ignoreCurlyBraces=true, ignoreIdentifierCase=true,
     ignoreModifiers=true, ignoreStringCase=true, threshold=6}
Found 6 duplicate lines in the following files:
 Between lines 201 and 207 in
     /Users/haruki_zaemon/Projects/redhill/simian/build/dist/src/java/
     awt/image/WritableRaster.java
 ...
Found 66375 duplicate lines in 5949 blocks in 1260 files
Processed a total of 390309 significant (1196065 raw) lines in 4242 files
Processing time: 9.490sec
Documentation: GroovyDoc ...

<taskdef name="groovydoc"
    classname="org.codehaus.groovy.ant.Groovydoc">
  <classpath>
    <path path="${mainClassesDirectory}" />
    <path refid="compilePath" />
  </classpath>
</taskdef>

<groovydoc destdir="${docsDirectory}/gapi"
    sourcepath="${mainSourceDirectory}"
    packagenames="**.*" use="true" windowtitle="${title} "
    doctitle="${title}" header="${title}" footer="${docFooter}"
    overview="src/main/overview.html" private="false">
  <link packages="java.,org.xml.,javax.,org.xml."
      href="http://java.sun.com/j2se/1.5.0/docs/api" />
  <link packages="org.apache.ant.,org.apache.tools.ant."
      href="http://www.dpml.net/api/ant/1.7.0" />
  <link packages="org.junit.,junit.framework."
      href="http://junit.sourceforge.net/junit3.8.1/javadoc/" />
</groovydoc>
... Documentation:
GroovyDoc
BUILDS
Builds: Groovy from Ant

• Need groovy jar on your Ant classpath
    <taskdef name="groovy"
             classname="org.codehaus.groovy.ant.Groovy"
             classpathref="my.classpath"/>

    <target name="printXmlFileNamesFromJar">
      <zipfileset id="found" src="foobar.jar"
                includes="**/*.xml"/>
      <groovy>
        project.references.found.each {
            println it.name
        }
      </groovy>
    </target>
Builds: Ant from Groovy

• Built-in (need ant.jar on your Groovy classpath)
  new AntBuilder().with {
      echo(file:'Temp.java', '''
      class Temp {
        public static void main(String[] args) {
           System.out.println("Hello");
        }
      }
      ''')
      javac(srcdir:'.', includes:'Temp.java', fork:'true')
      java(classpath:'.', classname:'Temp', fork:'true')
      echo('Done')
  }
  // =>
  //    [javac] Compiling 1 source file
  //      [java] Hello
  //      [echo] Done
Builds: Gant

• lightweight façade on Groovy's AntBuilder
• target def‘ns, pre-defined ‗ant‘, operations on
  predefined objects
    includeTargets << gant.targets.Clean
    cleanPattern << [ '**/*~' , '**/*.bak' ]
    cleanDirectory << 'build'

    target ( stuff : 'A target to do some stuff.' ) {
      println ( 'Stuff' )
      depends ( clean )
      echo ( message : 'A default message from Ant.' )
      otherStuff ( )
    }

    target ( otherStuff : 'A target to do some other stuff' ) {
      println ( 'OtherStuff' )
      echo ( message : 'Another message from Ant.' )
      clean ( )
    }
Builds: GMaven

• Implementing Maven plugins has never been
  Groovier!
• Groovy Mojos
  – A Simple Groovy Mojo
• Building Plugins
  – Project Definition
  – Mojo Parameters
• Putting More Groove into your Mojo
  – Using ant, Using fail()
• gmaven-archetype-mojo Archetype
• gmaven-plugin Packaging
Builds: GMaven

   <plugin>
      <groupId>org.codehaus.mojo.groovy</groupId>
      <artifactId>groovy-maven-plugin</artifactId>
      <executions>
         <execution>
            <id>restart-weblogic</id>
            <phase>pre-integration-test</phase>
            <goals>
               <goal>execute</goal>
            </goals>
            <configuration>
               <source>
               ${pom.basedir}/src/main/script/restartWeblogic.groovy
               </source>
            </configuration>
         </execution>
  ...
Builds: GMaven

def domainDir =
   project.properties['weblogic.domain.easyimage.dir']

stopWebLogic()
copyFiles(domainDir)
startWebLogic(domainDir)
waitForWebLogicStartup()

def stopWebLogic() {
   weblogicServerDir = project.properties['weblogic.server.dir']
   adminUrl = project.properties['easyimage.weblogic.admin.t3']
   userName = 'weblogic'
   password = 'weblogic'
   ant.exec(executable: 'cmd', failonerror: 'false') {
      arg(line: "/C ${wlsDir}/bin/setWLSEnv.cmd && java ..." ...
}

...
Builds: Gradle ...

• A very flexible general purpose build tool like Ant
• Switchable, build-by-convention frameworks a la Maven.
  But we never lock you in!
• Powerful support for multi-project builds
• Powerful dependency management (Apache Ivy based)
• Full support for your existing Maven or Ivy repository
  infrastructure
• Support for transitive dependency management without
  the need for remote repositories or pom.xml/ivy.xml files
• Ant tasks as first class citizens
• Groovy build scripts
• A rich domain model for describing your build
... Builds: Gradle
Builds: Hudson

• Gant Plugin — This plugin allows Hudson to invoke
  Gant build script as the main build step
• Gradle Plugin — This plugin allows Hudson to
  invoke Gradle build script as the main build step
• Grails Plugin — This plugin allows Hudson to invoke
  Grails tasks as build steps
• Hudson CLI and GroovyShell       Usage pattern?




   Source: http://weblogs.java.net/blog/kohsuke/archive/2009/05/hudson_cli_and.html
<project name="StringUtilsBuild" default="package"
                             xmlns:ivy="antlib:org.apache.ivy.ant" xmlns="antlib:org.apache.tools.ant">

                          <target name="clean">
                              <delete dir="target"/>
                              <delete dir="lib"/>
                          </target>

                          <target name="compile" depends="-init-ivy">
                               <mkdir dir="target/classes"/>
                               <javac srcdir="src/main"
                                      destdir="target/classes"/>
                          </target>

                          <target name="compileTest" depends="compile">
                               <mkdir dir="target/test-classes"/>
Ant Build File...




                               <javac srcdir="src/test"
                                      destdir="target/test-classes">
                                   <classpath>
                                        <pathelement location="target/classes"/>
                                        <fileset dir="lib" includes="*.jar"/>
                                   </classpath>
                               </javac>
                          </target>
                    ...
...
                          <target name="test" depends="compileTest">
                              <mkdir dir="target/test-reports"/>
                              <junit printsummary="yes" fork="yes" haltonfailure="yes">
                                  <classpath>
                                       <pathelement location="target/classes"/>
                                       <pathelement location="target/test-classes"/>
                                       <fileset dir="lib" includes="*.jar"/>
                                  </classpath>
                                  <formatter type="plain"/>
                                  <formatter type="xml"/>
                                  <batchtest fork="yes" todir="target/test-reports">
                                       <fileset dir="target/test-classes"/>
                                  </batchtest>
                              </junit>
                          </target>

                          <target name="package" depends="test">
                              <jar destfile="target/stringutils-1.0-SNAPSHOT.jar"
                                    basedir="target/classes"/>
                          </target>
...Ant Build File




                          <target name="-init-ivy" depends="-download-ivy">
                              <taskdef resource="org/apache/ivy/ant/antlib.xml"
                                       uri="antlib:org.apache.ivy.ant" classpath="lib/ivy.jar"/>
                              <ivy:settings file="ivysettings.xml"/>
                              <ivy:retrieve/>
                          </target>

                        <target name="-download-ivy">
                            <property name="ivy.version" value="2.1.0-rc2"/>
                            <mkdir dir="lib"/>
                            <get
                    src="http://repo2.maven.org/maven2/org/apache/ivy/ivy/${ivy.version}/ivy-
                    ${ivy.version}.jar"
                                  dest="lib/ivy.jar" usetimestamp="true"/>
                        </target>
                    </project>
<project xmlns="http://maven.apache.org/POM/4.0.0"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                                       http://maven.apache.org/maven-v4_0_0.xsd">
                <modelVersion>4.0.0</modelVersion>
                <groupId>org.groovycookbook.builds</groupId>
                <artifactId>stringutils</artifactId>
                <packaging>jar</packaging>
                <version>1.0-SNAPSHOT</version>
                <name>stringutils</name>
                <url>http://maven.apache.org</url>
                <dependencies>
                    <dependency>
                         <groupId>junit</groupId>
                         <artifactId>junit</artifactId>
                         <version>4.7</version>
                         <scope>test</scope>
                    </dependency>
                </dependencies>
                <build>
                    <plugins>
                         <!-- this is a java 1.5 project -->
Maven POM




                         <plugin>
                             <groupId>org.apache.maven.plugins</groupId>
                             <artifactId>maven-compiler-plugin</artifactId>
                             <configuration>
                                  <source>1.5</source>
                                  <target>1.5</target>
                             </configuration>
                         </plugin>
                    </plugins>
                </build>
            </project>
import static groovy.xml.NamespaceBuilder.newInstance as namespace

                   ant = new AntBuilder()
                   clean()
                   doPackage()

                   def doPackage() {
                       test()
                       ant.jar destfile: 'target/stringutils-1.0-SNAPSHOT.jar',
                           basedir: 'target/classes'
                   }

                   private dependencies() {
                       def ivy_version = '2.1.0-rc2'
                       def repo = 'http://repo2.maven.org/maven2'
                       ant.mkdir dir: 'lib'
                       ant.get dest: 'lib/ivy.jar',
                               usetimestamp: 'true',
                               src: "$repo/org/apache/ivy/ivy/$ivy_version/ivy-${ivy_version}.jar"
build.groovy ...




                       ant.taskdef classpath: 'lib/ivy.jar',
                               uri: 'antlib:org.apache.ivy.ant',
                               resource: 'org/apache/ivy/ant/antlib.xml'
                       def ivy = namespace(ant, 'antlib:org.apache.ivy.ant')
                       ivy.settings file: 'ivysettings.xml'
                       ivy.retrieve()
                   }

                   def clean() {
                       ant.delete dir: 'target'
                       ant.delete dir: 'lib'
                   }
                   ...
...
                   def compile() {
                       dependencies()
                       ant.mkdir dir: 'target/classes'
                       ant.javac destdir: 'target/classes', srcdir: 'src/main',
                           includeantruntime: false
                   }

                   def compileTest() {
                       compile()
                       ant.mkdir dir: 'target/test-classes'
                       ant.javac(destdir: 'target/test-classes', srcdir: 'src/test',
                           includeantruntime: false) {
                           classpath {
                               pathelement location: 'target/classes'
                               fileset dir: 'lib', includes: '*.jar'
                           }
                       }
                   }
... build.groovy




                   def test() {
                       compileTest()
                       ant.mkdir dir: 'target/test-reports'
                       ant.junit(printsummary: 'yes', haltonfailure: 'yes', fork: 'yes') {
                           classpath {
                                pathelement location: 'target/classes'
                                pathelement location: 'target/test-classes'
                                fileset dir: 'lib', includes: '*.jar'
                           }
                           formatter type: 'plain'
                           formatter type: 'xml'
                           batchtest(todir: 'target/test-reports', fork: 'yes') {
                                fileset dir: 'target/test-classes'
                           }
                       }
                   }
import static groovy.xml.NamespaceBuilder.newInstance as namespace

                 target('package': '') {
                     depends 'test'
                     jar destfile: 'target/stringutils-1.0-SNAPSHOT.jar',
                         basedir: 'target/classes'
                 }

                 target('-download-ivy': '') {
                     def ivy_version = '2.1.0-rc2'
                     def repo = 'http://repo2.maven.org/maven2'
                     mkdir dir: 'lib'
                     get dest: 'lib/ivy.jar', usetimestamp: 'true',
                         src: "$repo/org/apache/ivy/ivy/$ivy_version/ivy-${ivy_version}.jar"
                 }

                 target(clean: '') {
                     delete dir: 'target'
build.gant ...




                     delete dir: 'lib'
                 }

                 target(compile: '') {
                     depends '-init-ivy'
                     mkdir dir: 'target/classes'
                     javac destdir: 'target/classes', srcdir: 'src/main'
                 }
                 ...
...
                 target('-init-ivy': '') {
                     depends '-download-ivy'
                     taskdef classpath: 'lib/ivy.jar', uri: 'antlib:org.apache.ivy.ant',
                             resource: 'org/apache/ivy/ant/antlib.xml'
                     def ivy = namespace(ant, 'antlib:org.apache.ivy.ant')
                     ivy.settings file: 'ivysettings.xml'
                     ivy.retrieve()
                 }

                 target(compileTest: '') {
                     depends 'compile'
                     mkdir dir: 'target/test-classes'
                     javac(destdir: 'target/test-classes', srcdir: 'src/test') {
                         classpath {
                             pathelement location: 'target/classes'
                             fileset dir: 'lib', includes: '*.jar'
                         }
                     }
                 }

                 target(test: '') {
                     depends 'compileTest'
                     mkdir dir: 'target/test-reports'
                     junit(printsummary: 'yes', haltonfailure: 'yes', fork: 'yes') {
                         classpath {
... build.gant




                             pathelement location: 'target/classes'
                             pathelement location: 'target/test-classes'
                             fileset dir: 'lib', includes: '*.jar'
                         }
                         formatter type: 'plain'
                         formatter type: 'xml'
                         batchtest(todir: 'target/test-reports', fork: 'yes') {
                             fileset dir: 'target/test-classes'
                         }
                     }
                 }

                 setDefaultTarget 'package'
usePlugin 'java'

               sourceCompatibility = 1.5
               version = '1.0-SNAPSHOT'

               repositories {
                   mavenCentral()
               }
build.gradle




               dependencies {
                   testCompile 'junit:junit:4.7'
               }
MODULAR GROOVY
Modularisation: Grapes

   // Google Collections example
   import com.google.common.collect.HashBiMap
   @Grab(group='com.google.collections',
         module='google-collections',
         version='1.0-rc1')
   def getFruit() {
       [ grape:'purple',
         lemon:'yellow',
        orange:'orange' ] as HashBiMap
   }
   assert fruit.lemon == 'yellow'
   assert fruit.inverse().yellow == 'lemon'
Modularisation: OSGi

This is Apache Sling in five bullets:
• REST based web framework
• Content-driven, using a JCR content repository
• Powered by OSGi
• Scripting inside, multiple languages         See also: Grails JCR plugin
• Apache Open Source project




           See also: http://hamletdarcy.blogspot.com
PATTERNS
©
    Better Design Patterns:
A   Immutable...
S
E                                                                   // ...
R
    • Java Immutable Class
                                                                    @Override
T                                                                   public boolean equals(Object obj) {
                                                                        if (this == obj)

2     – As per Joshua Bloch
      public final class Punter {
          private final String first;
                                                                            return true;
                                                                        if (obj == null)

          Effective Java
0         private final String last;                                        return false;
0                                                                       if (getClass() != obj.getClass())
         public String getFirst() {                                         return false;
6            return first;                                              Punter other = (Punter) obj;
-        }                                                              if (first == null) {
2                                                                           if (other.first != null)
0        public String getLast() {                                              return false;
             return last;                                               } else if (!first.equals(other.first))
0        }                                                                  return false;
9                                                                       if (last == null) {
         @Override                                                          if (other.last != null)
         public int hashCode() {                                                return false;
             final int prime = 31;                                      } else if (!last.equals(other.last))
             int result = 1;                                                return false;
             result = prime * result + ((first == null)                 return true;
                 ? 0 : first.hashCode());                           }
             result = prime * result + ((last == null)
                 ? 0 : last.hashCode());                            @Override
             return result;                                         public String toString() {
         }                                                              return "Punter(first:" + first
                                                                            + ", last:" + last + ")";
         public Punter(String first, String last) {                 }
             this.first = first;
             this.last = last;                                  }
         }
         // ...


                                                AUG 2009 - 70
©
    ...Better Design Patterns:
A   Immutable...                                                                            boilerplate
S
E                                                                   // ...

    • Java Immutable Class
R                                                                   @Override
T                                                                   public boolean equals(Object obj) {
                                                                        if (this == obj)
      public final class Punter {                                           return true;
2         private final String first;                                   if (obj == null)
0         private final String last;                                        return false;
0                                                                       if (getClass() != obj.getClass())
         public String getFirst() {                                         return false;
6            return first;                                              Punter other = (Punter) obj;
-        }                                                              if (first == null) {
2                                                                           if (other.first != null)
0        public String getLast() {                                              return false;
             return last;                                               } else if (!first.equals(other.first))
0        }                                                                  return false;
9                                                                       if (last == null) {
         @Override                                                          if (other.last != null)
         public int hashCode() {                                                return false;
             final int prime = 31;                                      } else if (!last.equals(other.last))
             int result = 1;                                                return false;
             result = prime * result + ((first == null)                 return true;
                 ? 0 : first.hashCode());                           }
             result = prime * result + ((last == null)
                 ? 0 : last.hashCode());                            @Override
             return result;                                         public String toString() {
         }                                                              return "Punter(first:" + first
                                                                            + ", last:" + last + ")";
         public Punter(String first, String last) {                 }
             this.first = first;
             this.last = last;                                  }
         }
         // ...


                                                AUG 2009 - 71
©
    ...Better Design Patterns:
A   Immutable
S
E
R
T

2
0
0           @Immutable class Punter {
6
-               String first, last
2
0           }
0
9




                        AUG 2009 - 72
©
    Better Design Patterns:
A   Singleton
S
E
R   class Calculator {
T       def total = 0
2       def add(a, b) { total++; a + b }
0   }
0
6
-   def INSTANCE = new Calculator()
2
0   Calculator.metaClass.constructor = { -> INSTANCE }
0
9
    def c1 = new Calculator()
    def c2 = new Calculator()                   @Singleton(lazy=true)
                                                class X {
    assert c1.add(1, 2) == 3                       def getHello () {
    assert c2.add(3, 4) == 7                         "Hello, World!"
                                                   }
    assert c1.is(c2)                            }
    assert [c1, c2].total == [2, 2]
                                                println X.instance.hello

                                AUG 2009 - 73
Better Design Patterns: Delegate…
©
                                             public Date getWhen() {
    import java.util.Date;
A                                               return when;
S                                            }
E public class Event {
R    private String title;
                                             public void setWhen(Date when) {
T    private String url;
                                                this.when = when;
      private Date when;
2                                            }
0
0     public String getUrl() {
                                             public boolean before(Date other) {
6        return url;
                                                return when.before(other);
-     }
2                                            }
0
      public void setUrl(String url) {
0                                            public void setTime(long time) {
9        this.url = url;
                                                when.setTime(time);
      }
                                             }
      public String getTitle() {
                                             public long getTime() {
         return title;
                                                return when.getTime();
      }
                                             }
      public void setTitle(String title) {
                                         public boolean after(Date other) {
         this.title = title;
                                            return when.after(other);
      }
                                         }
      // ...
                                         // ...


                                    AUG 2009 - 74
…Better Design Patterns: Delegate…
©
                                                      public Date getWhen() {
    import java.util.Date;
A                                                        return when;
S                            boilerplate              }
E public class Event {
R    private String title;
                                                      public void setWhen(Date when) {
T    private String url;
                                                         this.when = when;
        private Date when;
2                                                     }
0
0       public String getUrl() {
                                                      public boolean before(Date other)
6          return url;
                                                 {
-       }
2                                                         return when.before(other);
0                                                     }
0
        public void setUrl(String url) {
9          this.url = url;
                                                      public void setTime(long time) {
        }
                                                         when.setTime(time);
                                                      }
        public String getTitle() {
           return title;
                                                      public long getTime() {
        }
                                                         return when.getTime();
                                                      }
        public void setTitle(String title)
    {
                                                      public boolean after(Date other) {
          this.title = title;
                                                         return when.after(other);
        }
                                                      }
        // ...
                                                      // ...

                                      AUG 2009 - 75
…Better Design Patterns: Delegate
©

A
S
E
R
T    class Event {
2
         String title, url
0
0
         @Delegate Date when
6    }
-
2
0
0    def gr8conf = new Event(title: "GR8 Conference",
9
             url: "http://www.gr8conf.org",
             when: Date.parse("yyyy/MM/dd", "2009/05/18"))

     def javaOne = new Event(title: "JavaOne",
             url: "http://java.sun.com/javaone/",
             when: Date.parse("yyyy/MM/dd", "2009/06/02"))

     assert gr8conf.before(javaOne.when)


                              AUG 2009 - 76
FURTHER INFO
©   More Information: on the web
A
S

    • Web sites
E
R
T
       –   http://groovy.codehaus.org
2      –   http://grails.codehaus.org
0
0      –   http://pleac.sourceforge.net/pleac_groovy (many examples)
6
-      –   http://www.asert.com.au/training/java/GV110.htm (workshop)
2
0   • Mailing list for users
0
9      – user@groovy.codehaus.org
    • Information portals
       – http://www.aboutgroovy.org
       – http://www.groovyblogs.org
    • Documentation (1000+ pages)
       – Getting Started Guide, User Guide, Developer Guide, Testing
         Guide, Cookbook Examples, Advanced Usage Guide


                                  AUG 2009 - 78
©
    More Information: Groovy in Action
A
S
E
R
T

2
0
0
6
-
2
0
0
9




     Second edition of GinA, ‘ReGinA’ now under development
                                                 AUG 2009 - 79

Weitere ähnliche Inhalte

Was ist angesagt?

Kotlin @ Coupang Backed - JetBrains Day seoul 2018
Kotlin @ Coupang Backed - JetBrains Day seoul 2018Kotlin @ Coupang Backed - JetBrains Day seoul 2018
Kotlin @ Coupang Backed - JetBrains Day seoul 2018Sunghyouk Bae
 
JUnit5 and TestContainers
JUnit5 and TestContainersJUnit5 and TestContainers
JUnit5 and TestContainersSunghyouk Bae
 
XSpect, a lightweight library to make your code reusable and maintainable.
XSpect, a lightweight library to make your code reusable and maintainable.XSpect, a lightweight library to make your code reusable and maintainable.
XSpect, a lightweight library to make your code reusable and maintainable.岡諭 李
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with GroovyArturo Herrero
 
(Greach 2015) Dsl'ing your Groovy
(Greach 2015) Dsl'ing your Groovy(Greach 2015) Dsl'ing your Groovy
(Greach 2015) Dsl'ing your GroovyAlonso Torres
 
Turtle Graphics in Groovy
Turtle Graphics in GroovyTurtle Graphics in Groovy
Turtle Graphics in GroovyJim Driscoll
 
Getting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NETGetting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NETTomas Jansson
 
Alternatives of JPA/Hibernate
Alternatives of JPA/HibernateAlternatives of JPA/Hibernate
Alternatives of JPA/HibernateSunghyouk Bae
 
Hello, Guava !
Hello, Guava !Hello, Guava !
Hello, Guava !輝 子安
 
Should I Use Scalding or Scoobi or Scrunch?
Should I Use Scalding or Scoobi or Scrunch? Should I Use Scalding or Scoobi or Scrunch?
Should I Use Scalding or Scoobi or Scrunch? DataWorks Summit
 
Python在豆瓣的应用
Python在豆瓣的应用Python在豆瓣的应用
Python在豆瓣的应用Qiangning Hong
 
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...Charles Nutter
 
Python高级编程(二)
Python高级编程(二)Python高级编程(二)
Python高级编程(二)Qiangning Hong
 
Kotlin is charming; The reasons Java engineers should start Kotlin.
Kotlin is charming; The reasons Java engineers should start Kotlin.Kotlin is charming; The reasons Java engineers should start Kotlin.
Kotlin is charming; The reasons Java engineers should start Kotlin.JustSystems Corporation
 
JDK1.7 features
JDK1.7 featuresJDK1.7 features
JDK1.7 featuresindia_mani
 

Was ist angesagt? (20)

Kotlin @ Coupang Backed - JetBrains Day seoul 2018
Kotlin @ Coupang Backed - JetBrains Day seoul 2018Kotlin @ Coupang Backed - JetBrains Day seoul 2018
Kotlin @ Coupang Backed - JetBrains Day seoul 2018
 
JUnit5 and TestContainers
JUnit5 and TestContainersJUnit5 and TestContainers
JUnit5 and TestContainers
 
XSpect, a lightweight library to make your code reusable and maintainable.
XSpect, a lightweight library to make your code reusable and maintainable.XSpect, a lightweight library to make your code reusable and maintainable.
XSpect, a lightweight library to make your code reusable and maintainable.
 
Requery overview
Requery overviewRequery overview
Requery overview
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with Groovy
 
(Greach 2015) Dsl'ing your Groovy
(Greach 2015) Dsl'ing your Groovy(Greach 2015) Dsl'ing your Groovy
(Greach 2015) Dsl'ing your Groovy
 
Turtle Graphics in Groovy
Turtle Graphics in GroovyTurtle Graphics in Groovy
Turtle Graphics in Groovy
 
Design Patterns
Design PatternsDesign Patterns
Design Patterns
 
Getting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NETGetting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NET
 
Scalding for Hadoop
Scalding for HadoopScalding for Hadoop
Scalding for Hadoop
 
Alternatives of JPA/Hibernate
Alternatives of JPA/HibernateAlternatives of JPA/Hibernate
Alternatives of JPA/Hibernate
 
Hello, Guava !
Hello, Guava !Hello, Guava !
Hello, Guava !
 
Should I Use Scalding or Scoobi or Scrunch?
Should I Use Scalding or Scoobi or Scrunch? Should I Use Scalding or Scoobi or Scrunch?
Should I Use Scalding or Scoobi or Scrunch?
 
Python在豆瓣的应用
Python在豆瓣的应用Python在豆瓣的应用
Python在豆瓣的应用
 
Hazelcast
HazelcastHazelcast
Hazelcast
 
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
 
Python高级编程(二)
Python高级编程(二)Python高级编程(二)
Python高级编程(二)
 
Kotlin is charming; The reasons Java engineers should start Kotlin.
Kotlin is charming; The reasons Java engineers should start Kotlin.Kotlin is charming; The reasons Java engineers should start Kotlin.
Kotlin is charming; The reasons Java engineers should start Kotlin.
 
JDK1.7 features
JDK1.7 featuresJDK1.7 features
JDK1.7 features
 
JRuby hacking guide
JRuby hacking guideJRuby hacking guide
JRuby hacking guide
 

Ähnlich wie Industrial Strength Groovy - Tools for the Professional Groovy Developer: Paul King

Java 7 Whats New(), Whats Next() from Oredev
Java 7 Whats New(), Whats Next() from OredevJava 7 Whats New(), Whats Next() from Oredev
Java 7 Whats New(), Whats Next() from OredevMattias Karlsson
 
Oscon Java Testing on the Fast Lane
Oscon Java Testing on the Fast LaneOscon Java Testing on the Fast Lane
Oscon Java Testing on the Fast LaneAndres Almiray
 
Understanding JavaScript Testing
Understanding JavaScript TestingUnderstanding JavaScript Testing
Understanding JavaScript TestingKissy Team
 
Virtualizing Java in Java (jug.ru)
Virtualizing Java in Java (jug.ru)Virtualizing Java in Java (jug.ru)
Virtualizing Java in Java (jug.ru)aragozin
 
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011Nick Sieger
 
Практики применения JRuby
Практики применения JRubyПрактики применения JRuby
Практики применения JRuby.toster
 
Devoxx UK 2013 Test-Driven Development with JavaEE 7, Arquillian and Embedded...
Devoxx UK 2013 Test-Driven Development with JavaEE 7, Arquillian and Embedded...Devoxx UK 2013 Test-Driven Development with JavaEE 7, Arquillian and Embedded...
Devoxx UK 2013 Test-Driven Development with JavaEE 7, Arquillian and Embedded...Peter Pilgrim
 
Terence Barr - jdk7+8 - 24mai2011
Terence Barr - jdk7+8 - 24mai2011Terence Barr - jdk7+8 - 24mai2011
Terence Barr - jdk7+8 - 24mai2011Agora Group
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing UpDavid Padbury
 
Groovy - Grails as a modern scripting language for Web applications
Groovy - Grails as a modern scripting language for Web applicationsGroovy - Grails as a modern scripting language for Web applications
Groovy - Grails as a modern scripting language for Web applicationsIndicThreads
 
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMockUnit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMockRobot Media
 
Atlassian Groovy Plugins
Atlassian Groovy PluginsAtlassian Groovy Plugins
Atlassian Groovy PluginsPaul King
 
Spring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFuSpring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFuVMware Tanzu
 
Clojure - A new Lisp
Clojure - A new LispClojure - A new Lisp
Clojure - A new Lispelliando dias
 
Jruby synergy-of-ruby-and-java
Jruby synergy-of-ruby-and-javaJruby synergy-of-ruby-and-java
Jruby synergy-of-ruby-and-javaKeith Bennett
 

Ähnlich wie Industrial Strength Groovy - Tools for the Professional Groovy Developer: Paul King (20)

Java 7 Whats New(), Whats Next() from Oredev
Java 7 Whats New(), Whats Next() from OredevJava 7 Whats New(), Whats Next() from Oredev
Java 7 Whats New(), Whats Next() from Oredev
 
Junit_.pptx
Junit_.pptxJunit_.pptx
Junit_.pptx
 
Oscon Java Testing on the Fast Lane
Oscon Java Testing on the Fast LaneOscon Java Testing on the Fast Lane
Oscon Java Testing on the Fast Lane
 
Understanding JavaScript Testing
Understanding JavaScript TestingUnderstanding JavaScript Testing
Understanding JavaScript Testing
 
Virtualizing Java in Java (jug.ru)
Virtualizing Java in Java (jug.ru)Virtualizing Java in Java (jug.ru)
Virtualizing Java in Java (jug.ru)
 
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
 
Практики применения JRuby
Практики применения JRubyПрактики применения JRuby
Практики применения JRuby
 
Devoxx UK 2013 Test-Driven Development with JavaEE 7, Arquillian and Embedded...
Devoxx UK 2013 Test-Driven Development with JavaEE 7, Arquillian and Embedded...Devoxx UK 2013 Test-Driven Development with JavaEE 7, Arquillian and Embedded...
Devoxx UK 2013 Test-Driven Development with JavaEE 7, Arquillian and Embedded...
 
Terence Barr - jdk7+8 - 24mai2011
Terence Barr - jdk7+8 - 24mai2011Terence Barr - jdk7+8 - 24mai2011
Terence Barr - jdk7+8 - 24mai2011
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing Up
 
55j7
55j755j7
55j7
 
Node.js vs Play Framework
Node.js vs Play FrameworkNode.js vs Play Framework
Node.js vs Play Framework
 
Groovy - Grails as a modern scripting language for Web applications
Groovy - Grails as a modern scripting language for Web applicationsGroovy - Grails as a modern scripting language for Web applications
Groovy - Grails as a modern scripting language for Web applications
 
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMockUnit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
 
Atlassian Groovy Plugins
Atlassian Groovy PluginsAtlassian Groovy Plugins
Atlassian Groovy Plugins
 
Spring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFuSpring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFu
 
Advanced Java Testing
Advanced Java TestingAdvanced Java Testing
Advanced Java Testing
 
Clojure - A new Lisp
Clojure - A new LispClojure - A new Lisp
Clojure - A new Lisp
 
Jruby synergy-of-ruby-and-java
Jruby synergy-of-ruby-and-javaJruby synergy-of-ruby-and-java
Jruby synergy-of-ruby-and-java
 
Jet presentation
Jet presentationJet presentation
Jet presentation
 

Mehr von Paul King

awesome groovy
awesome groovyawesome groovy
awesome groovyPaul King
 
groovy databases
groovy databasesgroovy databases
groovy databasesPaul King
 
groovy transforms
groovy transformsgroovy transforms
groovy transformsPaul King
 
functional groovy
functional groovyfunctional groovy
functional groovyPaul King
 
Make Testing Groovy
Make Testing GroovyMake Testing Groovy
Make Testing GroovyPaul King
 
Agile Testing Practices
Agile Testing PracticesAgile Testing Practices
Agile Testing PracticesPaul King
 
groovy DSLs from beginner to expert
groovy DSLs from beginner to expertgroovy DSLs from beginner to expert
groovy DSLs from beginner to expertPaul King
 
groovy and concurrency
groovy and concurrencygroovy and concurrency
groovy and concurrencyPaul King
 
Dynamic Language Practices
Dynamic Language PracticesDynamic Language Practices
Dynamic Language PracticesPaul King
 
Make Your Builds More Groovy
Make Your Builds More GroovyMake Your Builds More Groovy
Make Your Builds More GroovyPaul King
 
Groovy Power Features
Groovy Power FeaturesGroovy Power Features
Groovy Power FeaturesPaul King
 
Make Your Testing Groovy
Make Your Testing GroovyMake Your Testing Groovy
Make Your Testing GroovyPaul King
 
Groovy Testing Sep2009
Groovy Testing Sep2009Groovy Testing Sep2009
Groovy Testing Sep2009Paul King
 
Craig Smith & Paul King Agile Tool Hacking Taking Your Agile Development ...
Craig Smith & Paul King   Agile Tool Hacking   Taking Your Agile Development ...Craig Smith & Paul King   Agile Tool Hacking   Taking Your Agile Development ...
Craig Smith & Paul King Agile Tool Hacking Taking Your Agile Development ...Paul King
 
Groovy Tutorial
Groovy TutorialGroovy Tutorial
Groovy TutorialPaul King
 
XML and Web Services with Groovy
XML and Web Services with GroovyXML and Web Services with Groovy
XML and Web Services with GroovyPaul King
 

Mehr von Paul King (17)

awesome groovy
awesome groovyawesome groovy
awesome groovy
 
groovy databases
groovy databasesgroovy databases
groovy databases
 
groovy transforms
groovy transformsgroovy transforms
groovy transforms
 
functional groovy
functional groovyfunctional groovy
functional groovy
 
Make Testing Groovy
Make Testing GroovyMake Testing Groovy
Make Testing Groovy
 
Agile Testing Practices
Agile Testing PracticesAgile Testing Practices
Agile Testing Practices
 
groovy DSLs from beginner to expert
groovy DSLs from beginner to expertgroovy DSLs from beginner to expert
groovy DSLs from beginner to expert
 
groovy and concurrency
groovy and concurrencygroovy and concurrency
groovy and concurrency
 
GroovyDSLs
GroovyDSLsGroovyDSLs
GroovyDSLs
 
Dynamic Language Practices
Dynamic Language PracticesDynamic Language Practices
Dynamic Language Practices
 
Make Your Builds More Groovy
Make Your Builds More GroovyMake Your Builds More Groovy
Make Your Builds More Groovy
 
Groovy Power Features
Groovy Power FeaturesGroovy Power Features
Groovy Power Features
 
Make Your Testing Groovy
Make Your Testing GroovyMake Your Testing Groovy
Make Your Testing Groovy
 
Groovy Testing Sep2009
Groovy Testing Sep2009Groovy Testing Sep2009
Groovy Testing Sep2009
 
Craig Smith & Paul King Agile Tool Hacking Taking Your Agile Development ...
Craig Smith & Paul King   Agile Tool Hacking   Taking Your Agile Development ...Craig Smith & Paul King   Agile Tool Hacking   Taking Your Agile Development ...
Craig Smith & Paul King Agile Tool Hacking Taking Your Agile Development ...
 
Groovy Tutorial
Groovy TutorialGroovy Tutorial
Groovy Tutorial
 
XML and Web Services with Groovy
XML and Web Services with GroovyXML and Web Services with Groovy
XML and Web Services with Groovy
 

Kürzlich hochgeladen

Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024The Digital Insurer
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embeddingZilliz
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfSeasiaInfotech2
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesZilliz
 

Kürzlich hochgeladen (20)

Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embedding
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdf
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector Databases
 

Industrial Strength Groovy - Tools for the Professional Groovy Developer: Paul King

  • 1. Industrial Strength Groovy Tools for the Professional Groovy Developer Dr Paul King, ASERT: @paulk_asert
  • 2. Topics • Testing/Mocking: JUnit, TestNG, EasyB, Spock, Instinct, MockFor, Gmock, EasyMock • Injection: Spring, Guice • Coverage: Cobertura • Code style: CodeNarc, IntelliJ • Duplication: Simian • Documentation: GroovyDoc • Builds: Ant, Gant, GMaven, Gradle, Hudson • Modularisation: Grapes, OSGi
  • 4. © What is Groovy? A S E R T 2 0 0 6 - 2 0 • ―Groovy is like a super version 0 9 of Java. It can leverage Java's enterprise capabilities but also has cool productivity features like closures, DSL support, builders and dynamic typing.‖ SpringOne2gx_Oct2009 - 4
  • 5. © Groovy Goodies Overview A S E • Fully object oriented R T 2 0 • Closures: reusable • GPath: efficient 0 6 and assignable pieces object navigation - 2 of code • GroovyBeans • Operators can be 0 0 • grep and switch overloaded 9 • Templates, builder, • Multimethods swing, Ant, markup, • Literal declaration for XML, SQL, XML-RPC, lists (arrays), maps, Scriptom, Grails, ranges and regular tests, Mocks expressions SpringOne2gx_Oct2009 - 5
  • 6. Growing Acceptance … Making Java Groovy (soon) Now free
  • 7. © … Growing Acceptance … A S E R T 2 0 0 6 - 2 0 0 9 http://www.jroller.com/scolebourne/entry/devoxx_2008_whitebo SpringOne2gx_Oct2009 - 7 http://www.java.net
  • 8. © … Growing Acceptance … What alternative JVM language are you using or intending to use A S E R T 2 0 0 6 - 2 0 0 9 http://www.leonardoborges.com/writings SpringOne2gx_Oct2009 - 8
  • 9. © … Growing Acceptance … A S E R T 2 0 0 6 - 2 0 0 9 http://it-republik.de/jaxenter/quickvote/results/1/poll/44 (translated using http://babelfish.yahoo SpringOne2gx_Oct2009 - 9
  • 10. © … Growing Acceptance A S E R T 2 0 0 6 - 2 0 0 9 SpringOne2gx_Oct2009 - 10
  • 11. Groovy‘s Appeal • Innovators/Thought leaders – Ideas, power, flexibility, novelty, thinking community • Early adopters – Productivity benefits and collegiate community – Leverage JVM and potential for mainstream • Mainstream – Leverage existing Java skills, low learning curve – Leverage JVM and production infrastructure – Professional community – Tools, tools, tools
  • 12. TESTING SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
  • 13. Utilities Runners Groovy and Testing Tool Spectrum AllPairs, Combinations Native Groovy, JUnit, TestNG, Spock, EasyB, Polyglot languages JBehave, Cucumber, Robot Framework Logic programming Threads, Parallel / Concurrency Web Database SOAP / Other libraries Drivers Drivers REST Drivers Data-driven Drivers WebTest DbUnit FEST libraries WebDriver DataSets GroovyWS Email Networking libraries XML Processing JWebUnit SqlUnit XML-RPC FTP Read/write files / Tellurium groovy.sql CXF AntUnit Excel / Word / CSV Selenium JPA Axis2 Telnet Reporting, Logging HtmlUnit JDO JAX-WS SSH Watij BigTable JAX-RS Exec Tools HttpBuilder JDBC iTest2, SoapUI, Twist, IDEs, JMeter, Cyberneko Text editors, Recorders, Sahi, Build Tools, CI
  • 14. Testing: JUnit import org.junit.Test import static org.junit.Assert.assertEquals class ArithmeticTest { @Test void additionIsWorking() { assertEquals 4, 2+2 } @Test(expected=ArithmeticException) void divideByZero() { println 1/0 } }
  • 15. Testing: TestNG import ... public class SimpleTest { @BeforeClass public void setUp() { // code invoked when test is created } @Test(groups = [ "fast" ]) public void aFastTest() { System.out.println("Fast test"); } @Test(groups = [ "slow" ]) public void aSlowTest() { System.out.println("Slow test"); } }
  • 16. import static org.easymock.EasyMock.* mockControl = createStrictControl() mockReverser = mockControl.createMock(Reverser) storer = new JavaStorer(mockReverser) testStorage() def testStorage() { expectReverse(123.456, -123.456) Mocking: EasyMock expectReverse('hello', 'olleh') mockControl.replay() checkReverse(123.456, -123.456) checkReverse('hello', 'olleh') mockControl.verify() } def expectReverse(input, output) { expect(mockReverser.reverse(input)).andReturn(output) } def checkReverse(value, reverseValue) { storer.put(value) assert value == storer.get() assert reverseValue == storer.getReverse() }
  • 17. class a_default_storer { def storer @initially void create_new_storer() { storer = new Storer() } private check_persist_and_reverse(value, expectedReverse) { storer.put(value) def persisted = storer.get() assert persisted == value def reversed = storer.reverse assert reversed == expectedReverse Testing: Instinct } @spec def should_reverse_numbers() { check_persist_and_reverse 123.456, -123.456 } @spec def should_reverse_strings() { check_persist_and_reverse 'hello', 'olleh' } @spec def should_reverse_lists() { check_persist_and_reverse([1, 3, 5], [5, 3, 1]) } } check_specs_for a_default_storer
  • 18. import groovy.mock.interceptor.MockFor def mocker = new MockFor(Collaborator.class) // create the Mock support mocker.demand.one(1..2) { 1 } // demand the 'one' method one // or two times, returning 1 mocker.demand.two() { 2 } // demand the 'two' method // exactly once, returning 2 mocker.use { // start using the Mock def caller = new Caller() // caller will call Collaborator assertEquals 1, caller.collaborateOne() // will call Collaborator.one assertEquals 1, caller.collaborateOne() // will call Collaborator.one assertEquals 2, caller.collaborateTwo() // will call Collaborator.two Mocking: MockFor } // implicit verify here import groovy.mock.interceptor.MockFor def mocker = new MockFor(Collaborator.class) mocker.demand.one(1..2) { 1 } mocker.demand.two() { 2 } mocker.use { def caller = new Caller() assertEquals 1, caller.collaborateOne() assertEquals 1, caller.collaborateOne() assertEquals 2, caller.collaborateTwo() }
  • 19. Mocking: Gmock ... • Method mocking: mockLoader.load("fruit").returns("apple") • Exception mocking: mockLoader.load("unknown").raises(new RuntimeException()) • Stub mocking: mockLoader.load("fruit").returns("apple").stub() • Static method mocking: mockMath.static.random().returns(0.5) • Property mocking: mockLoader.name.returns("loader") • Constructor mocking: def mockFile = mock(File, constructor('/a/path/file.txt')) • Partial mocking: mock(controller).params.returns([id: 3]) • Times expectation: mockLoader.load("fruit").returns("apple").atLeastOnce() • Custom matcher: mockLoader.load(match{ it.startsWith("fru") }) • Strict ordering: ordered { ... } • Optional support for Hamcrest matcher: mockLoader.put("test", is(not(lessThan(5)))) • GMockController if you can't extend GMockTestCase in your test
  • 20. Mocking: Gmock import org.gmock.GMockTestCase class LoaderTest extends GMockTestCase { void testLoader(){ def mockLoader = mock() mockLoader.load('key').returns('value') play { assertEquals "value", mockLoader.load('key') } } }
  • 22. ... Testing: Spock @Speck @RunWith(Sputnik) class PublisherSubscriberSpeck { def "events are received by all subscribers"() { def pub = new Publisher() def sub1 = Mock(Subscriber) def sub2 = Mock(Subscriber) pub.subscribers << sub1 << sub2 when: pub.send("event") then: 1 * sub1.receive("event") 1 * sub2.receive("event") } }
  • 23. Testing: EasyB ... given "an invalid zip code", { invalidzipcode = "221o1" } and "given the zipcodevalidator is initialized", { zipvalidate = new ZipCodeValidator() } when "validate is invoked with the invalid zip code", { value = zipvalidate.validate(invalidzipcode) } then "the validator instance should return false", { value.shouldBe false }
  • 24. before "start selenium", { given "selenium is up and running", { // start selenium } } scenario "a valid person has been entered", { when "filling out the person form with a first and last name", { selenium.open("http://acme.racing.net/greport/personracereport.html") selenium.type("fname", "Britney") selenium.type("lname", "Smith") } Testing: EasyB ... and "the submit link has been clicked", { selenium.click("submit") } then "the report should have a list of races for that person", { selenium.waitForPageToLoad("5000") values = ["Mclean 1/2 Marathon", "Reston 5K", "Herndon 10K", "Leesburg 10K"] for(i in 0..<values.size()){ selenium.getText("//table//tr[${(i+3)}]/td").shouldBeEqualTo values[i] } } } after "stop selenium" , { then "selenium should be shutdown", { // stop selenium } }
  • 25. Dependency Injection • Hollywood Principle – Don‘t call us, we‘ll call you • “All problems in computer science can be solved by another level of indirection” • "...except for the problem of too many layers of indirection“ – For attributions, see http://en.wikipedia.org/wiki/Inversion_of_control
  • 26. Dependency Injection • Pattern for loosely coupled & testable objects class Client { class Client { Calculator calc = Calculator calc new CalculatorImpl() def executeCalc(a, b) { def executeCalc(a, b) { calc.add(a, b) calc.add(a, b) } } } }  Service locator/factory  Need to select setter, constructor, field style  Tightly coupled?  Can add complexity  Hard to test?  Manage configuration  Easy to understand?  Direct or framework  Refactoring/navigation?  Consistency/lifecycle
  • 27. Dependency Injection: Spring ... • Several flavors – let‘s look at Annotation and BeanBuilder flavors import org.springframework.stereotype.Component @Component class AdderImpl { def add(x, y) { x + y } } import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Component @Component class CalcImpl3 { @Autowired private AdderImpl adder def doAdd(x, y) { adder.add(x, y) } }
  • 28. ... Dependency Injection: Spring import org.springframework.context.support.GenericApplicationContext import org.springframework.context.annotation.ClassPathBeanDefinitionScanner def ctx = new GenericApplicationContext() new ClassPathBeanDefinitionScanner(ctx).scan('') ctx.refresh() def calc = ctx.getBean('calcImpl3') println calc.doAdd(3, 4) // => 7 def bb = new grails.spring.BeanBuilder() bb.beans { adder(AdderImpl) calcBean(CalcImpl2) { delegate.adder = adder } } def ctx = bb.createApplicationContext() def calc = ctx.getBean('calcBean') println calc.doAdd(3, 4) // => 7
  • 29. Dependency Injection: Guice import com.google.inject.* @ImplementedBy(CalculatorImpl) interface Calculator { def add(a, b) } @Singleton class CalculatorImpl implements Calculator { private total = 0 def add(a, b) { total++; a + b } def getTotalCalculations() { 'Total Calculations: ' + total } String toString() { 'Calc: ' + hashCode()} } class Client { @Inject Calculator calc // ... } def injector = Guice.createInjector() // ...
  • 30. Dependency Injection: Metaprogramming Style class Calculator { def total = 0 def add(a, b) { total++; a + b } } def INSTANCE = new Calculator() Calculator.metaClass.constructor = { -> INSTANCE } def c1 = new Calculator() def c2 = new Calculator() assert c1.add(1, 2) == 3 assert c2.add(3, 4) == 7 assert c1.is(c2) assert [c1, c2].total == [2, 2]
  • 33. ...Coverage: Cobertura ... Maven cobertura-instrument java –cp ... Command-line cobertura-report cobertura-check cobertura-merge Grails grails install-plugin code-coverage --global
  • 35. Remember 100% coverage rule ... • Necessary but not sufficient condition // 100%
  • 36. ...Remember 100% coverage rule ... • Necessary but not sufficient condition // 100% // Fail
  • 37. ...Remember 100% coverage rule • Necessary but not sufficient condition
  • 38. Code style: CodeNarc ... About 50 rules (1 broken?)
  • 39. ... Code style: CodeNarc ...
  • 40. ... Code style: CodeNarc
  • 42. Duplication: Simian ... Simian fully supports the following languages: • Java • C# • C++ with partial support • C for: • Objective-C • JavaScript (ECMAScript) • JSP • COBOL, ABAP • ASP • Ruby • HTML • Lisp • XML • SQL • Visual Basic • Groovy
  • 45. ... Duplication: Simian Similarity Analyser 2.2.23 - http://www.redhillconsulting.com.au/products/simian/index.html Copyright (c) 2003-08 RedHill Consulting Pty. Ltd. All rights reserved. Simian is not free unless used solely for non-commercial or evaluation purposes. {failOnDuplication=true, ignoreCharacterCase=true, ignoreCurlyBraces=true, ignoreIdentifierCase=true, ignoreModifiers=true, ignoreStringCase=true, threshold=6} Found 6 duplicate lines in the following files: Between lines 201 and 207 in /Users/haruki_zaemon/Projects/redhill/simian/build/dist/src/java/ awt/image/WritableRaster.java ... Found 66375 duplicate lines in 5949 blocks in 1260 files Processed a total of 390309 significant (1196065 raw) lines in 4242 files Processing time: 9.490sec
  • 46. Documentation: GroovyDoc ... <taskdef name="groovydoc" classname="org.codehaus.groovy.ant.Groovydoc"> <classpath> <path path="${mainClassesDirectory}" /> <path refid="compilePath" /> </classpath> </taskdef> <groovydoc destdir="${docsDirectory}/gapi" sourcepath="${mainSourceDirectory}" packagenames="**.*" use="true" windowtitle="${title} " doctitle="${title}" header="${title}" footer="${docFooter}" overview="src/main/overview.html" private="false"> <link packages="java.,org.xml.,javax.,org.xml." href="http://java.sun.com/j2se/1.5.0/docs/api" /> <link packages="org.apache.ant.,org.apache.tools.ant." href="http://www.dpml.net/api/ant/1.7.0" /> <link packages="org.junit.,junit.framework." href="http://junit.sourceforge.net/junit3.8.1/javadoc/" /> </groovydoc>
  • 49. Builds: Groovy from Ant • Need groovy jar on your Ant classpath <taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpathref="my.classpath"/> <target name="printXmlFileNamesFromJar"> <zipfileset id="found" src="foobar.jar" includes="**/*.xml"/> <groovy> project.references.found.each { println it.name } </groovy> </target>
  • 50. Builds: Ant from Groovy • Built-in (need ant.jar on your Groovy classpath) new AntBuilder().with { echo(file:'Temp.java', ''' class Temp { public static void main(String[] args) { System.out.println("Hello"); } } ''') javac(srcdir:'.', includes:'Temp.java', fork:'true') java(classpath:'.', classname:'Temp', fork:'true') echo('Done') } // => // [javac] Compiling 1 source file // [java] Hello // [echo] Done
  • 51. Builds: Gant • lightweight façade on Groovy's AntBuilder • target def‘ns, pre-defined ‗ant‘, operations on predefined objects includeTargets << gant.targets.Clean cleanPattern << [ '**/*~' , '**/*.bak' ] cleanDirectory << 'build' target ( stuff : 'A target to do some stuff.' ) { println ( 'Stuff' ) depends ( clean ) echo ( message : 'A default message from Ant.' ) otherStuff ( ) } target ( otherStuff : 'A target to do some other stuff' ) { println ( 'OtherStuff' ) echo ( message : 'Another message from Ant.' ) clean ( ) }
  • 52. Builds: GMaven • Implementing Maven plugins has never been Groovier! • Groovy Mojos – A Simple Groovy Mojo • Building Plugins – Project Definition – Mojo Parameters • Putting More Groove into your Mojo – Using ant, Using fail() • gmaven-archetype-mojo Archetype • gmaven-plugin Packaging
  • 53. Builds: GMaven <plugin> <groupId>org.codehaus.mojo.groovy</groupId> <artifactId>groovy-maven-plugin</artifactId> <executions> <execution> <id>restart-weblogic</id> <phase>pre-integration-test</phase> <goals> <goal>execute</goal> </goals> <configuration> <source> ${pom.basedir}/src/main/script/restartWeblogic.groovy </source> </configuration> </execution> ...
  • 54. Builds: GMaven def domainDir = project.properties['weblogic.domain.easyimage.dir'] stopWebLogic() copyFiles(domainDir) startWebLogic(domainDir) waitForWebLogicStartup() def stopWebLogic() { weblogicServerDir = project.properties['weblogic.server.dir'] adminUrl = project.properties['easyimage.weblogic.admin.t3'] userName = 'weblogic' password = 'weblogic' ant.exec(executable: 'cmd', failonerror: 'false') { arg(line: "/C ${wlsDir}/bin/setWLSEnv.cmd && java ..." ... } ...
  • 55. Builds: Gradle ... • A very flexible general purpose build tool like Ant • Switchable, build-by-convention frameworks a la Maven. But we never lock you in! • Powerful support for multi-project builds • Powerful dependency management (Apache Ivy based) • Full support for your existing Maven or Ivy repository infrastructure • Support for transitive dependency management without the need for remote repositories or pom.xml/ivy.xml files • Ant tasks as first class citizens • Groovy build scripts • A rich domain model for describing your build
  • 57. Builds: Hudson • Gant Plugin — This plugin allows Hudson to invoke Gant build script as the main build step • Gradle Plugin — This plugin allows Hudson to invoke Gradle build script as the main build step • Grails Plugin — This plugin allows Hudson to invoke Grails tasks as build steps • Hudson CLI and GroovyShell Usage pattern? Source: http://weblogs.java.net/blog/kohsuke/archive/2009/05/hudson_cli_and.html
  • 58. <project name="StringUtilsBuild" default="package" xmlns:ivy="antlib:org.apache.ivy.ant" xmlns="antlib:org.apache.tools.ant"> <target name="clean"> <delete dir="target"/> <delete dir="lib"/> </target> <target name="compile" depends="-init-ivy"> <mkdir dir="target/classes"/> <javac srcdir="src/main" destdir="target/classes"/> </target> <target name="compileTest" depends="compile"> <mkdir dir="target/test-classes"/> Ant Build File... <javac srcdir="src/test" destdir="target/test-classes"> <classpath> <pathelement location="target/classes"/> <fileset dir="lib" includes="*.jar"/> </classpath> </javac> </target> ...
  • 59. ... <target name="test" depends="compileTest"> <mkdir dir="target/test-reports"/> <junit printsummary="yes" fork="yes" haltonfailure="yes"> <classpath> <pathelement location="target/classes"/> <pathelement location="target/test-classes"/> <fileset dir="lib" includes="*.jar"/> </classpath> <formatter type="plain"/> <formatter type="xml"/> <batchtest fork="yes" todir="target/test-reports"> <fileset dir="target/test-classes"/> </batchtest> </junit> </target> <target name="package" depends="test"> <jar destfile="target/stringutils-1.0-SNAPSHOT.jar" basedir="target/classes"/> </target> ...Ant Build File <target name="-init-ivy" depends="-download-ivy"> <taskdef resource="org/apache/ivy/ant/antlib.xml" uri="antlib:org.apache.ivy.ant" classpath="lib/ivy.jar"/> <ivy:settings file="ivysettings.xml"/> <ivy:retrieve/> </target> <target name="-download-ivy"> <property name="ivy.version" value="2.1.0-rc2"/> <mkdir dir="lib"/> <get src="http://repo2.maven.org/maven2/org/apache/ivy/ivy/${ivy.version}/ivy- ${ivy.version}.jar" dest="lib/ivy.jar" usetimestamp="true"/> </target> </project>
  • 60. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.groovycookbook.builds</groupId> <artifactId>stringutils</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>stringutils</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.7</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <!-- this is a java 1.5 project --> Maven POM <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins> </build> </project>
  • 61. import static groovy.xml.NamespaceBuilder.newInstance as namespace ant = new AntBuilder() clean() doPackage() def doPackage() { test() ant.jar destfile: 'target/stringutils-1.0-SNAPSHOT.jar', basedir: 'target/classes' } private dependencies() { def ivy_version = '2.1.0-rc2' def repo = 'http://repo2.maven.org/maven2' ant.mkdir dir: 'lib' ant.get dest: 'lib/ivy.jar', usetimestamp: 'true', src: "$repo/org/apache/ivy/ivy/$ivy_version/ivy-${ivy_version}.jar" build.groovy ... ant.taskdef classpath: 'lib/ivy.jar', uri: 'antlib:org.apache.ivy.ant', resource: 'org/apache/ivy/ant/antlib.xml' def ivy = namespace(ant, 'antlib:org.apache.ivy.ant') ivy.settings file: 'ivysettings.xml' ivy.retrieve() } def clean() { ant.delete dir: 'target' ant.delete dir: 'lib' } ...
  • 62. ... def compile() { dependencies() ant.mkdir dir: 'target/classes' ant.javac destdir: 'target/classes', srcdir: 'src/main', includeantruntime: false } def compileTest() { compile() ant.mkdir dir: 'target/test-classes' ant.javac(destdir: 'target/test-classes', srcdir: 'src/test', includeantruntime: false) { classpath { pathelement location: 'target/classes' fileset dir: 'lib', includes: '*.jar' } } } ... build.groovy def test() { compileTest() ant.mkdir dir: 'target/test-reports' ant.junit(printsummary: 'yes', haltonfailure: 'yes', fork: 'yes') { classpath { pathelement location: 'target/classes' pathelement location: 'target/test-classes' fileset dir: 'lib', includes: '*.jar' } formatter type: 'plain' formatter type: 'xml' batchtest(todir: 'target/test-reports', fork: 'yes') { fileset dir: 'target/test-classes' } } }
  • 63. import static groovy.xml.NamespaceBuilder.newInstance as namespace target('package': '') { depends 'test' jar destfile: 'target/stringutils-1.0-SNAPSHOT.jar', basedir: 'target/classes' } target('-download-ivy': '') { def ivy_version = '2.1.0-rc2' def repo = 'http://repo2.maven.org/maven2' mkdir dir: 'lib' get dest: 'lib/ivy.jar', usetimestamp: 'true', src: "$repo/org/apache/ivy/ivy/$ivy_version/ivy-${ivy_version}.jar" } target(clean: '') { delete dir: 'target' build.gant ... delete dir: 'lib' } target(compile: '') { depends '-init-ivy' mkdir dir: 'target/classes' javac destdir: 'target/classes', srcdir: 'src/main' } ...
  • 64. ... target('-init-ivy': '') { depends '-download-ivy' taskdef classpath: 'lib/ivy.jar', uri: 'antlib:org.apache.ivy.ant', resource: 'org/apache/ivy/ant/antlib.xml' def ivy = namespace(ant, 'antlib:org.apache.ivy.ant') ivy.settings file: 'ivysettings.xml' ivy.retrieve() } target(compileTest: '') { depends 'compile' mkdir dir: 'target/test-classes' javac(destdir: 'target/test-classes', srcdir: 'src/test') { classpath { pathelement location: 'target/classes' fileset dir: 'lib', includes: '*.jar' } } } target(test: '') { depends 'compileTest' mkdir dir: 'target/test-reports' junit(printsummary: 'yes', haltonfailure: 'yes', fork: 'yes') { classpath { ... build.gant pathelement location: 'target/classes' pathelement location: 'target/test-classes' fileset dir: 'lib', includes: '*.jar' } formatter type: 'plain' formatter type: 'xml' batchtest(todir: 'target/test-reports', fork: 'yes') { fileset dir: 'target/test-classes' } } } setDefaultTarget 'package'
  • 65. usePlugin 'java' sourceCompatibility = 1.5 version = '1.0-SNAPSHOT' repositories { mavenCentral() } build.gradle dependencies { testCompile 'junit:junit:4.7' }
  • 67. Modularisation: Grapes // Google Collections example import com.google.common.collect.HashBiMap @Grab(group='com.google.collections', module='google-collections', version='1.0-rc1') def getFruit() { [ grape:'purple', lemon:'yellow', orange:'orange' ] as HashBiMap } assert fruit.lemon == 'yellow' assert fruit.inverse().yellow == 'lemon'
  • 68. Modularisation: OSGi This is Apache Sling in five bullets: • REST based web framework • Content-driven, using a JCR content repository • Powered by OSGi • Scripting inside, multiple languages See also: Grails JCR plugin • Apache Open Source project See also: http://hamletdarcy.blogspot.com
  • 70. © Better Design Patterns: A Immutable... S E // ... R • Java Immutable Class @Override T public boolean equals(Object obj) { if (this == obj) 2 – As per Joshua Bloch public final class Punter { private final String first; return true; if (obj == null) Effective Java 0 private final String last; return false; 0 if (getClass() != obj.getClass()) public String getFirst() { return false; 6 return first; Punter other = (Punter) obj; - } if (first == null) { 2 if (other.first != null) 0 public String getLast() { return false; return last; } else if (!first.equals(other.first)) 0 } return false; 9 if (last == null) { @Override if (other.last != null) public int hashCode() { return false; final int prime = 31; } else if (!last.equals(other.last)) int result = 1; return false; result = prime * result + ((first == null) return true; ? 0 : first.hashCode()); } result = prime * result + ((last == null) ? 0 : last.hashCode()); @Override return result; public String toString() { } return "Punter(first:" + first + ", last:" + last + ")"; public Punter(String first, String last) { } this.first = first; this.last = last; } } // ... AUG 2009 - 70
  • 71. © ...Better Design Patterns: A Immutable... boilerplate S E // ... • Java Immutable Class R @Override T public boolean equals(Object obj) { if (this == obj) public final class Punter { return true; 2 private final String first; if (obj == null) 0 private final String last; return false; 0 if (getClass() != obj.getClass()) public String getFirst() { return false; 6 return first; Punter other = (Punter) obj; - } if (first == null) { 2 if (other.first != null) 0 public String getLast() { return false; return last; } else if (!first.equals(other.first)) 0 } return false; 9 if (last == null) { @Override if (other.last != null) public int hashCode() { return false; final int prime = 31; } else if (!last.equals(other.last)) int result = 1; return false; result = prime * result + ((first == null) return true; ? 0 : first.hashCode()); } result = prime * result + ((last == null) ? 0 : last.hashCode()); @Override return result; public String toString() { } return "Punter(first:" + first + ", last:" + last + ")"; public Punter(String first, String last) { } this.first = first; this.last = last; } } // ... AUG 2009 - 71
  • 72. © ...Better Design Patterns: A Immutable S E R T 2 0 0 @Immutable class Punter { 6 - String first, last 2 0 } 0 9 AUG 2009 - 72
  • 73. © Better Design Patterns: A Singleton S E R class Calculator { T def total = 0 2 def add(a, b) { total++; a + b } 0 } 0 6 - def INSTANCE = new Calculator() 2 0 Calculator.metaClass.constructor = { -> INSTANCE } 0 9 def c1 = new Calculator() def c2 = new Calculator() @Singleton(lazy=true) class X { assert c1.add(1, 2) == 3 def getHello () { assert c2.add(3, 4) == 7 "Hello, World!" } assert c1.is(c2) } assert [c1, c2].total == [2, 2] println X.instance.hello AUG 2009 - 73
  • 74. Better Design Patterns: Delegate… © public Date getWhen() { import java.util.Date; A return when; S } E public class Event { R private String title; public void setWhen(Date when) { T private String url; this.when = when; private Date when; 2 } 0 0 public String getUrl() { public boolean before(Date other) { 6 return url; return when.before(other); - } 2 } 0 public void setUrl(String url) { 0 public void setTime(long time) { 9 this.url = url; when.setTime(time); } } public String getTitle() { public long getTime() { return title; return when.getTime(); } } public void setTitle(String title) { public boolean after(Date other) { this.title = title; return when.after(other); } } // ... // ... AUG 2009 - 74
  • 75. …Better Design Patterns: Delegate… © public Date getWhen() { import java.util.Date; A return when; S boilerplate } E public class Event { R private String title; public void setWhen(Date when) { T private String url; this.when = when; private Date when; 2 } 0 0 public String getUrl() { public boolean before(Date other) 6 return url; { - } 2 return when.before(other); 0 } 0 public void setUrl(String url) { 9 this.url = url; public void setTime(long time) { } when.setTime(time); } public String getTitle() { return title; public long getTime() { } return when.getTime(); } public void setTitle(String title) { public boolean after(Date other) { this.title = title; return when.after(other); } } // ... // ... AUG 2009 - 75
  • 76. …Better Design Patterns: Delegate © A S E R T class Event { 2 String title, url 0 0 @Delegate Date when 6 } - 2 0 0 def gr8conf = new Event(title: "GR8 Conference", 9 url: "http://www.gr8conf.org", when: Date.parse("yyyy/MM/dd", "2009/05/18")) def javaOne = new Event(title: "JavaOne", url: "http://java.sun.com/javaone/", when: Date.parse("yyyy/MM/dd", "2009/06/02")) assert gr8conf.before(javaOne.when) AUG 2009 - 76
  • 78. © More Information: on the web A S • Web sites E R T – http://groovy.codehaus.org 2 – http://grails.codehaus.org 0 0 – http://pleac.sourceforge.net/pleac_groovy (many examples) 6 - – http://www.asert.com.au/training/java/GV110.htm (workshop) 2 0 • Mailing list for users 0 9 – user@groovy.codehaus.org • Information portals – http://www.aboutgroovy.org – http://www.groovyblogs.org • Documentation (1000+ pages) – Getting Started Guide, User Guide, Developer Guide, Testing Guide, Cookbook Examples, Advanced Usage Guide AUG 2009 - 78
  • 79. © More Information: Groovy in Action A S E R T 2 0 0 6 - 2 0 0 9 Second edition of GinA, ‘ReGinA’ now under development AUG 2009 - 79