SlideShare une entreprise Scribd logo
1  sur  138
Télécharger pour lire hors ligne
© ASERT 2006-2010




                    Groovy Power Features!
                                   Dr Paul King
                               paulk@asert.com.au
                                  @paulk_asert
                                 ASERT, Australia
Topics
                    Groovy Intro
                    • Leveraging the language
                    • Use and abuse of Design Patterns
                    • Web Services
                    • Writing DSLs
© ASERT 2006-2010




                    • Groovy Testing
                    • Polyglot Groovy
                    • Parallel Processing
                    • Enterprise Groovy
                    • More Info
                                                         QCON 2010 - 2
What is Groovy?
                    • “Groovy is like a super version
                      of Java. It can leverage Java's
                      enterprise capabilities but also
                      has cool productivity features like closures,
                      DSL support, builders and dynamic typing.”
© ASERT 2006-2010




                     Groovy = Java –   boiler plate code
                                   +   mostly dynamic typing
                                   +   closures
                                   +   domain specific languages
                                   +   builders
                                   +   metaprogramming
                                   +   GDK library
                                                                QCON 2010 - 3
Groovy Goodies Overview
                    • Fully object oriented
                    • Closures: reusable
                      and assignable
                      pieces of code
                    • Operators can be          • GPath: efficient
                      overloaded
© ASERT 2006-2010




                                                  object navigation
                    • Multimethods              • GroovyBeans
                    • Literal declaration for   • grep and switch
                      lists (arrays), maps,
                      ranges and regular        • Templates, builder,
                      expressions                 swing, Ant, markup,
                                                  XML, SQL, XML-RPC,
                                                  Scriptom, Grails,
                                                  tests, Mocks   QCON 2010 - 4
Growing Acceptance …
  A slow and steady start but now gaining in
  momentum, maturity and mindshare




Now free
… Growing Acceptance …
© ASERT 2006-2010




                                             QCON 2010 - 6
… Growing Acceptance …
© ASERT 2006-2010




                     Groovy and Grails downloads:
                     70-90K per month and growing   QCON 2010 - 7
… Growing Acceptance …
© ASERT 2006-2010




                             Source: http://www.micropoll.com/akira/mpresult/501697-116746




                                                      Source: http://www.grailspodcast.com/
                                                                                       QCON 2010 - 8
… Growing Acceptance …
© ASERT 2006-2010




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




                                                                     http://www.java.net
                                                                                           QCON 2010 - 9
… Growing Acceptance …
                What alternative JVM language are you using or intending to use
© ASERT 2006-2010




                                 http://www.leonardoborges.com/writings
                                                                          QCON 2010 - 10
… Growing Acceptance …
© ASERT 2006-2010




                    http://it-republik.de/jaxenter/quickvote/results/1/poll/44 (translated using http://babelfish.yahoo.com)
                                                                                                                               QCON 2010 - 11
… Growing Acceptance …
© ASERT 2006-2010




                      http://pollpigeon.com/jsf-grails-wicket/r/25665/
                                                                         QCON 2010 - 12
… Growing Acceptance
© ASERT 2006-2010




                                           QCON 2010 - 13
The Landscape of JVM Languages

                                                                                                           mostly
                                                                                                          dynamic
                                                                                                            typing
© ASERT 2006-2010




                                      Dynamic features call
                                      for dynamic types                                  Java bytecode calls
                                                                                             for static types




                    The terms “Java Virtual Machine” and “JVM” mean a Virtual Machine for the Java™ platform.
                                                                                                                QCON 2010 - 14
Groovy Starter
                    System.out.println("Hello, World!");   // optional semicolon,
                    println 'Hello, World!'                // System.out, brackets,
                                                           // main() method, class defn

                    def name = 'Guillaume'                 // dynamic typing
                    println "$name, I'll get the car."     // GString

                    String longer = """${name}, the car
                    is in the next row."""                 // multi-line string
© ASERT 2006-2010




                                                           // with static typing

                    assert 0.5 == 1/2                      // BigDecimal equals()

                    def printSize(obj) {                   // optional duck typing
                        print obj?.size()                  // safe dereferencing
                    }

                    def pets = ['ant', 'bee', 'cat']       //   native list syntax
                    pets.each { pet ->                     //   closure support
                        assert pet < 'dog'                 //   overloading '<' on String
                    }                                      //   or: for (pet in pets)...
                                                                                    QCON 2010 - 15
A Better Java...
                    import java.util.List;
                    import java.util.ArrayList;

                    class Erase {
                        private List removeLongerThan(List strings, int length) {    This code
                            List result = new ArrayList();
                            for (int i = 0; i < strings.size(); i++) {
                                                                                       is valid
                                String s = (String) strings.get(i);                  Java and
                                if (s.length() <= length) {
                                    result.add(s);                                  valid Groovy
                                }
                            }
© ASERT 2006-2010




                            return result;
                        }
                        public static void main(String[] args) {
                            List names = new ArrayList();
                            names.add("Ted"); names.add("Fred");
                            names.add("Jed"); names.add("Ned");
                            System.out.println(names);
                                                                                     Based on an
                            Erase e = new Erase();                                   example by
                            List shortNames = e.removeLongerThan(names, 3);          Jim Weirich
                            System.out.println(shortNames.size());
                            for (int i = 0; i < shortNames.size(); i++) {            & Ted Leung
                                String s = (String) shortNames.get(i);
                                System.out.println(s);
                            }
                        }
                    }
                                                                                          QCON 2010 - 16
...A Better Java...
                    import java.util.List;
                    import java.util.ArrayList;

                    class Erase {
                        private List removeLongerThan(List strings, int length) {        Do the
                            List result = new ArrayList();
                            for (int i = 0; i < strings.size(); i++) {
                                                                                      semicolons
                                String s = (String) strings.get(i);                  add anything?
                                if (s.length() <= length) {
                                    result.add(s);                                   And shouldn‟t
                                }
                            }                                                         we us more
© ASERT 2006-2010




                        }
                            return result;                                            modern list
                        public static void main(String[] args) {                       notation?
                            List names = new ArrayList();
                            names.add("Ted"); names.add("Fred");                        Why not
                            names.add("Jed"); names.add("Ned");
                            System.out.println(names);
                                                                                    import common
                            Erase e = new Erase();                                     libraries?
                            List shortNames = e.removeLongerThan(names, 3);
                            System.out.println(shortNames.size());
                            for (int i = 0; i < shortNames.size(); i++) {
                                String s = (String) shortNames.get(i);
                                System.out.println(s);
                            }
                        }
                    }
                                                                                          QCON 2010 - 17
...A Better Java...
                    class Erase {
                        private List removeLongerThan(List strings, int length) {
                            List result = new ArrayList()
                            for (String s in strings) {
                                if (s.length() <= length) {
                                    result.add(s)
                                }
                            }
                            return result
                        }

                        public static void main(String[] args) {
© ASERT 2006-2010




                            List names = new ArrayList()
                            names.add("Ted"); names.add("Fred")
                            names.add("Jed"); names.add("Ned")
                            System.out.println(names)
                            Erase e = new Erase()
                            List shortNames = e.removeLongerThan(names, 3)
                            System.out.println(shortNames.size())
                            for (String s in shortNames) {
                                System.out.println(s)
                            }
                        }
                    }




                                                                                    QCON 2010 - 18
...A Better Java...
                    class Erase {
                        private List removeLongerThan(List strings, int length) {
                            List result = new ArrayList()
                            for (String s in strings) {
                                if (s.length() <= length) {
                                    result.add(s)
                                                                                      Do we need
                                }                                                   the static types?
                            }
                            return result                                           Must we always
                        }
                                                                                      have a main
                        public static void main(String[] args) {                       method and
© ASERT 2006-2010




                            List names = new ArrayList()
                            names.add("Ted"); names.add("Fred")                     class definition?
                            names.add("Jed"); names.add("Ned")
                            System.out.println(names)                                  How about
                            Erase e = new Erase()
                            List shortNames = e.removeLongerThan(names, 3)
                                                                                        improved
                            System.out.println(shortNames.size())                     consistency?
                            for (String s in shortNames) {
                                System.out.println(s)
                            }
                        }
                    }




                                                                                             QCON 2010 - 19
...A Better Java...
                    def removeLongerThan(strings, length) {
                        def result = new ArrayList()
                        for (s in strings) {
                            if (s.size() <= length) {
                                result.add(s)
                            }
                        }
                        return result
                    }
© ASERT 2006-2010




                    names = new ArrayList()
                    names.add("Ted")
                    names.add("Fred")
                    names.add("Jed")
                    names.add("Ned")
                    System.out.println(names)
                    shortNames = removeLongerThan(names, 3)
                    System.out.println(shortNames.size())
                    for (s in shortNames) {
                        System.out.println(s)
                    }



                                                              QCON 2010 - 20
...A Better Java...
                    def removeLongerThan(strings, length) {
                        def result = new ArrayList()
                        for (s in strings) {
                            if (s.size() <= length) {
                                result.add(s)                    Shouldn‟t we
                            }
                        }                                        have special
                        return result                         notation for lists?
                    }
                                                                  And special
© ASERT 2006-2010




                    names = new ArrayList()                       facilities for
                    names.add("Ted")
                    names.add("Fred")                          list processing?
                    names.add("Jed")                                Is „return‟
                    names.add("Ned")
                    System.out.println(names)                  needed at end?
                    shortNames = removeLongerThan(names, 3)
                    System.out.println(shortNames.size())
                    for (s in shortNames) {
                        System.out.println(s)
                    }



                                                                            QCON 2010 - 21
...A Better Java...
                    def removeLongerThan(strings, length) {
                        strings.findAll{ it.size() <= length }
                    }

                    names = ["Ted", "Fred", "Jed", "Ned"]
                    System.out.println(names)
                    shortNames = removeLongerThan(names, 3)
                    System.out.println(shortNames.size())
                    shortNames.each{ System.out.println(s) }
© ASERT 2006-2010




                                                                 QCON 2010 - 22
...A Better Java...
                    def removeLongerThan(strings, length) {
                        strings.findAll{ it.size() <= length }
                    }
                                                                  Is the method
                    names = ["Ted", "Fred", "Jed", "Ned"]         now needed?
                    System.out.println(names)
                    shortNames = removeLongerThan(names, 3)      Easier ways to
                    System.out.println(shortNames.size())          use common
                    shortNames.each{ System.out.println(s) }
                                                                    methods?
© ASERT 2006-2010




                                                                   Are brackets
                                                                 required here?




                                                                         QCON 2010 - 23
...A Better Java...
                    names = ["Ted", "Fred", "Jed", "Ned"]
                    println names
                    shortNames = names.findAll{ it.size() <= 3 }
                    println shortNames.size()
                    shortNames.each{ println it }
© ASERT 2006-2010




                                                              QCON 2010 - 24
...A Better Java
                    names = ["Ted", "Fred", "Jed", "Ned"]
                    println names
                    shortNames = names.findAll{ it.size() <= 3 }
                    println shortNames.size()
                    shortNames.each{ println it }
© ASERT 2006-2010




                           [Ted, Fred, Jed, Ned]
                           3
                           Ted
                           Jed
                           Ned




                                                              QCON 2010 - 25
Topics
                    • Groovy Intro
                    Leveraging the language
                    • Use and abuse of Design Patterns
                    • Web Services
                    • Writing DSLs
© ASERT 2006-2010




                    • Groovy Testing
                    • Polyglot Groovy
                    • Parallel Processing
                    • Enterprise Groovy
                    • More Info
                                                         QCON 2010 - 26
Better Control Structures: Switch

                             switch (10) {
                                case 0           : assert   false   ;   break
                                case 0..9        : assert   false   ;   break
                                case [8,9,11]    : assert   false   ;   break
                                case Float       : assert   false   ;   break
                                case {it%3 == 0} : assert   false   ;   break
                                case ~/../       : assert   true    ;   break
© ASERT 2006-2010




                                default          : assert   false   ;   break
                             }




                    • Extensible
                      – Implement your own isCase() method



                                                                                QCON 2010 - 27
Better Control Structures: Switch – Custom isCase
                                                                         WARNING:
                    enum Color {                                         Advanced
                       yellow, orange, purple                             Topic!
                       def isCase(thing) { thing.color == this }
                    }
                    import static Color.*
                    class Banana { def color = yellow }
                    class Orange { def color = orange }
                    class Grape { def color = purple }
© ASERT 2006-2010




                    fruits = [new Banana(), new Orange(), new Grape()]
                    fruits.each { println inspectFruit(it) }
                    def inspectFruit(f) {
                       switch (f) {
                          case yellow: return 'Found something yellow'
                          case orange: return 'Found something orange'
                          default: return 'Unknown color'
                       }
                    }
                                                         Found something yellow
                                                         Found something orange
                                                         Unknown color
                                                                           QCON 2010 - 28
Better Control Structures: Switch – Custom isCase

                    enum Color { yellow, orange, purple }
                    import static Color.*
                    class Banana { def color = yellow }
                    class Orange { def color = orange }
                    class Grape { def color = purple }
                    fruits = [new Banana(), new Orange(), new Grape()]
                    fruits.each { println inspectFruit(it) }
                    def inspectFruit(f) {
© ASERT 2006-2010




                       switch (f.color) {
                          case [yellow, orange]:
                             return "Found something $f.color"
                          default: return 'Unknown color'
                       }
                    }



                                                         Found something yellow
                                                         Found something orange
                                                         Unknown color
                                                                          QCON 2010 - 29
Better Control Structures: Switch – Custom isCase
                    enum Color {                                           WARNING:
                       yellow, orange, purple                           Advanced Topic!
                       def isCase(thing) {
                          thing?.hasProperty('color') && thing.color == this }
                    }

                    enum State {
                       peeled, unpeeled
                       def isCase(thing) {
                          try {
© ASERT 2006-2010




                             return thing.color == this
                          } catch (MissingPropertyException) {
                             return false
                          }
                    }

                    import static Color.*
                    import static State.*

                    class Banana { def color = yellow; def state = peeled }
                    class Orange { def color = orange }
                    class Grape { def state = peeled }
                    ...
                                                                                QCON 2010 - 30
Better Control Structures: Switch – Custom isCase
                                                                        WARNING:
                      ...
                                                                      Advanced Topic!
                      fruits = [new Banana(), new Orange(), new Grape()]
                      fruits.each { println inspectFruit(it) }

                      def inspectFruit(f) {
                         def yellowAndPeeled = { yellow.isCase(it) &&
                                                  peeled.isCase(it) }
                         switch (f) {
© ASERT 2006-2010




                            case yellowAndPeeled:
                               return 'Possibly found a banana split'
                            case yellow:
                               return 'Found something yellow'
                            case peeled:
                               return 'Found something peeled'
                            default:
                               return 'No comment'
                         }                           Possibly found a banana split
                      }                              No comment
                                                   Found something peeled
                                                                              QCON 2010 - 31
Better Control Structures: Switch Poker…
                                                               hand1         hand2



                                                          8C TS KC 9H 4S 7D 2S 5D 3S AC

                    suits = 'SHDC'
                    ranks = '23456789TJQKA'
                    suit = { String card -> suits.indexOf(card[1]) }
                    rank = { String card -> ranks.indexOf(card[0]) }
                    rankSizes = { List cards ->
© ASERT 2006-2010




                        cards.groupBy(rank).collect{ k, v -> v.size() }.sort() }
                    rankValues = { List cards ->
                        cards.collect{ rank(it) }.sort() }
                    // ...


                    println rankSizes(["7S", "7H", "2H", "7D", "AH"])
                    // => [1, 1, 3]




                                                                                   QCON 2010 - 32
…Better Control Structures: Switch Poker…



                    // ...
                    flush = { List cards -> cards.groupBy(suit).size() == 1 }
                    straight = { def v = rankValues(it); v == v[0]..v[0]+4 }
                    straightFlush = { List cards -> straight(cards) && flush(cards) }
© ASERT 2006-2010




                    fourOfAKind = { List cards -> rankSizes(cards) == [1, 4] }
                    fullHouse = { List cards -> rankSizes(cards) == [2, 3] }
                    threeOfAKind = { List cards -> rankSizes(cards) == [1, 1, 3] }
                    twoPair = { List cards -> rankSizes(cards) == [1, 2, 2] }
                    pair = { List cards -> rankSizes(cards) == [1, 1, 1, 2] }
                    // ...




                                                                               QCON 2010 - 33
… Better Control Structures: Switch Poker

                          // ...
                          def rankHand(List cards) {
                              switch (cards) {
                                  case straightFlush   :   return   9
                                  case fourOfAKind     :   return   8
                                  case fullHouse       :   return   7
                                  case flush           :   return   6
© ASERT 2006-2010




                                  case straight        :   return   5
                                  case threeOfAKind    :   return   4
                                  case twoPair         :   return   3
                                  case pair            :   return   2
                                  default              :   return   1
                              }
                          }
                          // ...




                                                                        QCON 2010 - 34
Topics
                    • Groovy Intro
                    • Leveraging the language
                    Use and abuse of Design Patterns
                    • Web Services
                    • Writing DSLs
© ASERT 2006-2010




                    • Groovy Testing
                    • Polyglot Groovy
                    • Parallel Processing
                    • Enterprise Groovy
                    • More Info
                                                        QCON 2010 - 35
Grapes / Grab
                    // Google Collections example
                    import com.google.common.collect.HashBiMap

                    @Grab(group='com.google.collections',
                          module='google-collections',
                          version='1.0-rc2')
© ASERT 2006-2010




                    def getFruit() {
                        [ grape:'purple',
                          lemon:'yellow',
                         orange:'orange' ] as HashBiMap
                    }

                    assert fruit.lemon == 'yellow'
                    assert fruit.inverse().yellow == 'lemon'
                                                            QCON 2010 - 36
Better Design Patterns: Immutable...
                    • Java Immutable Class
                      – As per Joshua Bloch                                   // ...
                                                                              @Override
                        Effective Java                                        public boolean equals(Object obj) {
                                                                                  if (this == obj)
                      public final class Punter {                                     return true;
                          private final String first;                             if (obj == null)
                          private final String last;                                  return false;
                                                                                  if (getClass() != obj.getClass())
                         public String getFirst() {                                   return false;
                             return first;                                        Punter other = (Punter) obj;
                         }                                                        if (first == null) {
© ASERT 2006-2010




                                                                                      if (other.first != null)
                         public String getLast() {                                        return false;
                             return last;                                         } else if (!first.equals(other.first))
                         }                                                            return false;
                                                                                  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;                            }
                         }
                         // ...
                                                                                                               QCON 2010 - 37
...Better Design Patterns: Immutable...
                    • Java Immutable Class                                                             boilerplate
                      – As per Joshua Bloch                                   // ...
                                                                              @Override
                        Effective Java                                        public boolean equals(Object obj) {
                                                                                  if (this == obj)
                      public final class Punter {                                     return true;
                          private final String first;                             if (obj == null)
                          private final String last;                                  return false;
                                                                                  if (getClass() != obj.getClass())
                         public String getFirst() {                                   return false;
                             return first;                                        Punter other = (Punter) obj;
                         }                                                        if (first == null) {
© ASERT 2006-2010




                                                                                      if (other.first != null)
                         public String getLast() {                                        return false;
                             return last;                                         } else if (!first.equals(other.first))
                         }                                                            return false;
                                                                                  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;                            }
                         }
                         // ...
                                                                                                               QCON 2010 - 38
...Better Design Patterns: Immutable



                         @Immutable class Punter {
                             String first, last
© ASERT 2006-2010




                         }




                                                      QCON 2010 - 39
Better Design Patterns: Singleton
                    class Calculator {
                        def total = 0
                        def add(a, b) { total++; a + b }
                    }

                    def INSTANCE = new Calculator()
                    Calculator.metaClass.constructor = { -> INSTANCE }
© ASERT 2006-2010




                    def c1 = new Calculator()
                    def c2 = new Calculator()
                                                      @Singleton(lazy=true)
                    assert c1.add(1, 2) == 3          class X {
                    assert c2.add(3, 4) == 7             def getHello () {
                                                           "Hello, World!"
                    assert c1.is(c2)                     }
                    assert [c1, c2].total == [2, 2]   }

                                                      println X.instance.hello

                                                                         QCON 2010 - 40
Better Design Patterns: Delegate…
                                                             public Date getWhen() {
                    import java.util.Date;
                                                                return when;
                                                             }
                    public class Event {
                       private String title;
                                                             public void setWhen(Date when) {
                       private String url;
                                                                this.when = when;
                       private Date when;
                                                             }
                      public String getUrl() {
                                                             public boolean before(Date other) {
                         return url;
                                                                return when.before(other);
                      }
© ASERT 2006-2010




                                                             }
                      public void setUrl(String url) {
                                                             public void setTime(long time) {
                         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);
                      }
                                                             }
                      // ...
                                                             // ...
                                                                                         QCON 2010 - 41
…Better Design Patterns: Delegate…
                                                             public Date getWhen() {
                    import java.util.Date;
                                                                return when;
                                               boilerplate   }
                    public class Event {
                       private String title;
                                                             public void setWhen(Date when) {
                       private String url;
                                                                this.when = when;
                       private Date when;
                                                             }
                      public String getUrl() {
                                                             public boolean before(Date other) {
                         return url;
                                                                return when.before(other);
                      }
© ASERT 2006-2010




                                                             }
                      public void setUrl(String url) {
                                                             public void setTime(long time) {
                         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);
                      }
                                                             }
                      // ...
                                                             // ...
                                                                                         QCON 2010 - 42
…Better Design Patterns: Delegate

                    class Event {
                        String title, url
                        @Delegate Date when
                    }
© ASERT 2006-2010




                    def gr8conf = new Event(title: "GR8 Conference",
                            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)

                                                                        QCON 2010 - 43
Topics
                    • Groovy Intro
                    • Leveraging the language
                    • Use and abuse of Design Patterns
                    Web Services
                    • Writing DSLs
© ASERT 2006-2010




                    • Groovy Testing
                    • Polyglot Groovy
                    • Parallel Processing
                    • Enterprise Groovy
                    • More Info
                                                         QCON 2010 - 44
SOAP Client and Server
                             class MathService {
                                 double add(double a, double b) {
                                     a + b
                                 }
                                 double square(double c) {
                                     c * c
                                 }
                             }
© ASERT 2006-2010




                             import groovy.net.soap.SoapServer

                             def server = new SoapServer('localhost', 6789)
                             server.setNode('MathService')
                             server.start()


                    import groovy.net.soap.SoapClient

                    def math = new SoapClient('http://localhost:6789/MathServiceInterface?wsdl')
                    assert math.add(1.0, 2.0) == 3.0
                    assert math.square(3.0) == 9.0

                                                                                        QCON 2010 - 45
Better Testing: SoapUI
                    • Tool for testing Web Services has a built-
                      in Groovy editor for custom steps
© ASERT 2006-2010




                                                            QCON 2010 - 46
Topics
                    • Groovy Intro
                    • Leveraging the language
                    • Use and abuse of Design Patterns
                    • Web Services
                    Writing DSLs
© ASERT 2006-2010




                    • Groovy Testing
                    • Polyglot Groovy
                    • Parallel Processing
                    • Enterprise Groovy
                    • More Info
                                                         QCON 2010 - 47
Groovy DSL Features
                    •   Literal Syntax Conventions
                    •   Scripts as well as Classes & Optional Syntax
                    •   Optional Typing & Named Arguments
                    •   Type Transformations
                    •   Using With
© ASERT 2006-2010




                    •   Operator Overloading
                    •   Closures
                    •   Runtime Metaprogramming
                    •   Compile-time Metaprogramming (AST Macros)
                    •   Builders

                                                               QCON 2010 - 48
Literal Syntax Conventions
                    • Lists
                      – Special syntax for list literals
                      – Additional common methods (operator overloading)
                              def list = [3, new Date(), 'Jan']
                              assert list + list == list * 2

                    • Maps
© ASERT 2006-2010




                      – Special syntax for map literals
                      – Additional common methods
                              def map = [a: 1, b: 2]
                              assert map['a'] == 1 && map.b == 2

                    • Ranges
                      – Special syntax for various kinds of ranges
                              def letters = 'a'..'z'
                              def numbers = 0..<10
                                                                     QCON 2010 - 49
Scripts as well as Classes & Optional Syntax
                    • Java
                       public class HelloJava {
                           public static void main(String[] args) {
                               System.out.println("Hello World");
                           }
                       }
© ASERT 2006-2010




                    • Groovy
                       class HelloGroovy {
                           static main(String[] args) {
                               System.out.println("Hello World");
                           }
                       }
                       System.out.println('Hello World');
                       println 'Hello World'
                                                                      QCON 2010 - 50
Optional Typing & Named Params
                    • Java
                    import java.util.Date;
                    import java.util.HashMap;
                    import java.util.Map;

                    public class OptionalSyntax {
                        public static void printDetails(Map<String, String> args) {
                            System.out.println("Details as at: " + new Date());
                            String first = args.get("first");
                            System.out.println("First name: " + (first != null ? first : "unknown"));
© ASERT 2006-2010




                            String last = args.get("last");
                            System.out.println("Last name: " + (last != null ? last : "unknown"));
                        }

                        public static void main(String[] args) {
                            Map<String, String> details = new HashMap<String, String>();
                            details.put("first", "John");
                            details.put("last", "Smith");
                            printDetails(details);
                        }
                    }                def printDetails(args) {
                                         println """Details as at: ${new Date()}
                                     First name: $args.first

                    • Groovy
                                     Last name: $args.last"""
                                     }
                                     printDetails first:'John', last:'Smith'

                                                                                            QCON 2010 - 51
Closures
                    • Traditional mainstream languages
                      – Data can be stored in variables, passed around,
                        combined in structured ways to form more complex
                        data; code stays put where it is defined
                    • Languages supporting closures
                      – Data and code can be stored in variables, passed
© ASERT 2006-2010




                        around, combined in structured ways to form more
                        complex algorithms and data
                        doubleNum = { num -> num * 2 }
                        println doubleNum(3) // => 6

                        processThenPrint = { num, closure ->
                            num = closure(num); println "num is $num"
                        }
                        processThenPrint(3, doubleNum)    // => num is 6
                        processThenPrint(10) { it / 2 }   // => num is 5
                                                                           QCON 2010 - 52
Static Imports




                    import groovy.swing.SwingXBuilder
© ASERT 2006-2010




                    import static java.awt.Color.*
                    import static java.lang.Math.*

                    def swing = new SwingXBuilder()
                    def frame = swing.frame(size: [300, 300]) {
                        graph(plots: [
                            [GREEN, {value -> sin(value)}],
                            [BLUE, {value -> cos(value)}],
                            [RED,   {value -> tan(value)}]
                        ])
                    }.show()
                                                                  QCON 2010 - 53
Using '.with' Example
                    letters = ['a', 'b', 'c']
                    range = 'b'..'d'
                    letters.with {
                        add 'd'
                        remove 'a'
                    }
                    assert letters == range
© ASERT 2006-2010




                    map = [a:10, b:4, c:7]
                    map.with {
                        assert (a + b) / c == 2
                    }




                                                     QCON 2010 - 54
Coin example...

                    enum Coin {
                      penny(1), nickel(5), dime(10), quarter(25)
                      Coin(int value) { this.value = value }
                      int value
                    }
© ASERT 2006-2010




                    import static Coin.*

                    assert 2 * quarter.value +
                           1 * nickel.value +
                           2 * penny.value == 57



                                                           QCON 2010 - 55
...Coin example...
                    class CoinMath {
                      static multiply(Integer self, Coin c) {
                        self * c.value
                      }
                    }
                    use (CoinMath) {
© ASERT 2006-2010




                      assert 2 * quarter +
                             1 * nickel +
                             2 * penny == 57
                    }
                    // EMC equivalent
                    Integer.metaClass.multiply = {
                      Coin c -> delegate * c.value
                    }
                    assert 2 * quarter + 1 * nickel + 2 * penny == 57
                                                                 QCON 2010 - 56
...Coin example
                    class CoinValues {
                       static get(Integer self, String name) {
                          self * Coin."${singular(name)}".value
                       }
                       static singular(String val) {
                          val.endsWith('ies') ? val[0..-4] + 'y' : val.endsWith('s') ? val[0..-2] : val
                       }
                    }

                    use (CoinValues) {
© ASERT 2006-2010




                      assert 2.quarters + 1.nickel + 2.pennies == 57
                    }

                    // EMC equivalent
                    Integer.metaClass.getProperty = { String name ->
                       def mp = Integer.metaClass.getMetaProperty(name)
                       if (mp) return mp.getProperty(delegate)
                       def singular = name.endsWith('ies') ? name[0..-4] + 'y' :
                            name.endsWith('s') ? name[0..-2] : name
                       delegate * Coin."$singular".value
                    }

                    assert 2.quarters + 1.nickel + 2.pennies == 57                               QCON 2010 - 57
Game example...
                    // Trying out the game DSL idea by Sten Anderson from:
                    // http://blogs.citytechinc.com/sanderson/?p=92
                    class GameUtils {
                      static VOWELS = ['a', 'e', 'i', 'o', 'u']
                      static listItems(things) {
                        def result = ''
                        things.eachWithIndex{ thing, index ->
                          if (index > 0) {
© ASERT 2006-2010




                            if (index == things.size() - 1) result += ' and '
                            else if (index < things.size() - 1) result += ', '
                          }
                          result += "${thing.toLowerCase()[0] in VOWELS ? 'an' : 'a'} $thin
                        }
                        result ?: 'nothing'
                      }
                    }
                    import static GameUtils.*
                    ...
                                                                                 QCON 2010 - 58
...Game example...
                    ...
                    class Room {
                      def description
                      def contents = []
                    }
                    ...
© ASERT 2006-2010




                                                           QCON 2010 - 59
...Game example...
                    ...
                    class Player {
                      def currentRoom
                      def inventory = []
                      void look() {
                        println "You are in ${currentRoom?.description?:'the void'} which contains ${listItems(currentRoom?.contents)}
                      }
                      void inv() {
© ASERT 2006-2010




                        println "You are holding ${listItems(inventory)}"
                      }
                      void take(item) {
                        if (currentRoom?.contents?.remove(item)) {
                          inventory << item
                          println "You took the $item"
                        } else {
                          println "I see no $item here"
                        }
                      }
                                                                                                                      QCON 2010 - 60
...Game example...
                    ...
                    void drop(item) {
                        if (inventory?.remove(item)) {
                          currentRoom?.contents << item
                          println "You dropped the $item"
                        } else {
                          println "You don't have the $item"
                        }
© ASERT 2006-2010




                      }
                      def propertyMissing(String name) {
                        if (metaClass.respondsTo(this, name)) {
                          this."$name"()
                        }
                        name
                      }
                    }
                    ...
                                                                  QCON 2010 - 61
...
                                       ...Game example...
                    Room plainRoom = new Room(description:'a plain white room',
                                                  contents:['dagger', 'emerald', 'key'])
                    Player player = new Player(currentRoom:plainRoom)
                    player.with{
                      inv
                      look
                      take dagger
                      inv
© ASERT 2006-2010




                      look
                      take emerald
                      inv
                      look
                      take key
                      drop emerald
                      inv
                      look
                    }
                    assert player.inventory == ['dagger', 'key']                QCON 2010 - 62
...Game example
                    ...

                    // now try some error conditions
                    plainRoom.description = null
                    player.with {
                      drop gold
                      take gold
                      drop emerald
© ASERT 2006-2010




                      take emerald
                      take emerald
                      look
                    }




                                                        QCON 2010 - 63
Grails Criteria
                    // Account is a POJO in our domain/model

                    def c = Account.createCriteria()
                    def results = c {
                      like("holderFirstName", "Fred%")
                      and {
                        between("balance", 500, 1000)
                        eq("branch", "London")
© ASERT 2006-2010




                      }
                      maxResults(10)
                      order("holderLastName", "desc")
                    }
                    // source: Grails doco: 5. Object Relational Mapping (GORM): 5.4.2 Criteria




                                                                                       QCON 2010 - 64
Grails Criteria Example
                    // Book is a POJO in our domain/model

                    def book = Book.findByTitle("The Stand")

                    book = Book.findByTitleLike("Harry Pot%")

                    book = Book.findByReleaseDateBetween( firstDate, secondDate )
© ASERT 2006-2010




                    book = Book.findByReleaseDateGreaterThan( someDate )

                    book = Book.findByTitleLikeOrReleaseDateLessThan(
                        "%Something%", someDate )

                    books = Book.findAllByTitleLikeAndReleaseDateGreaterThan(
                        "%Java%", new Date()-30)
                    // source: Grails doco: 5. Object Relational Mapping (GORM): 5.4.1 Dynamic Finders


                                                                                                         QCON 2010 - 65
Grails Bean Builder Example
                    bb.beans {
                        marge(Person) {
                            name = "marge"
                            husband = { Person p ->
                                name = "homer"
                                age = 45
                                props = [overweight:true, height:"1.8m"]
                            }
                            children = [bart, lisa]
© ASERT 2006-2010




                        }
                        bart(Person) {
                            name = "Bart"
                            age = 11
                        }
                        lisa(Person) {
                            name = "Lisa"
                            age = 9
                        }
                    }
                    // source: 14. Grails and Spring: 14.3 Runtime Spring with the Beans DSL   QCON 2010 - 66
Groovy Lab Example
                    // require GroovyLab
                    import static org.math.array.Matrix.*
                    import static org.math.plot.Plot.*

                    def A = rand(10,3)       // random Matrix of 10 rows and 3 columns
                    def B = fill(10,3,1.0)   // one Matrix of 10 rows and 3 columns
                    def C = A + B            // support for matrix addition with "+" or "-"
                    def D = A - 2.0          // support for number addition with "+" or "-"
                    def E = A * B            // support for matrix multiplication or division
© ASERT 2006-2010




                    def F = rand(3,3)
                    def G = F**(-1)          // support for matrix power (with integers only)
                    println A                // display Matrix content
                    plot("A",A,"SCATTER")        // plot Matrix values as ScatterPlot

                    def M = rand(5,5) + id(5) //Eigenvalues decomposition
                    println "M=n" + M
                    println "V=n" + V(M)
                    println "D=n" + D(M)
                    println "M~n" + (V(M) * D(M) * V(M)**(-1))
                                                                                        QCON 2010 - 67
Operator Overloading Example
                    BigDecimal a = new BigDecimal(3.5d);
                    BigDecimal b = new BigDecimal(4.0d);
                    assert a.multiply(b).compareTo(new BigDecimal(14.0d)) == 0;
                    assert a.multiply(b).equals(new BigDecimal(14.0d).setScale(1));

                    def c = 3.5, d = 4.0
                    assert c * d == 14.0
© ASERT 2006-2010




                                                                             QCON 2010 - 68
Type Transformation Example
                    class InventoryItem {
                       def weight, name
                       InventoryItem(Map m) {
                          this.weight = m.weight; this.name = m.name
                       }
                       InventoryItem(weight, name) {
                          this.weight = weight; this.name = name
                       }
                       InventoryItem(String s) {
© ASERT 2006-2010




                          s.find(/weight=(d*)/) { all, w -> this.weight = w }
                          s.find(/name=(.*)/) { all, n -> this.name = n }
                       }
                    }
                    def room = [:]
                    def gold = [weight:50, name:'Gold'] as InventoryItem
                    def emerald = [10, 'Emerald'] as InventoryItem
                    def dagger = ['weight=5, name=Dagger'] as InventoryItem
                    room.contents = [gold, emerald, dagger]
                    room.contents.each{ println it.dump() }
                                                                                 QCON 2010 - 69
AST Builder
• Numerous approaches, still evolving.
  “From code” approach:

     def result = new AstBuilder().buildFromCode {
         println "Hello World"
     }

• Produces:
   BlockStatement
      -> ReturnStatement
         -> MethodCallExpression
            -> VariableExpression("this")
            -> ConstantExpression("println")
            -> ArgumentListExpression
                -> ConstantExpression("Hello World")
Topics
                    • Groovy Intro
                    • Leveraging the language
                    • Use and abuse of Design Patterns
                    • Web Services
                    • Writing DSLs
© ASERT 2006-2010




                    Groovy Testing
                    • Polyglot Groovy
                    • Parallel Processing
                    • Enterprise Groovy
                    • More Info
                                                         QCON 2010 - 71
Types of Testing

                        Unit Testing
                    Mock/interaction testing   Techniques
                     State-based testing       Testing DSLs
                                                ATDD/BDD
                                                Data-driven
                                               Logic-driven
© ASERT 2006-2010




                     Integration Testing
                                               Model-driven
                                               Performance
                                                  testing
                     Acceptance Testing
                                                All-pairs &
                        Web drivers
                                               combinations
                       Non-web drivers
                                                  Gpars
                        Test runners


                                                          QCON 2010 - 72
Groovy's Value Add for Testing
                    • Unit testing
                      – Built-in asserts, support for JUnit 3&4 and TestNG,
                        GroovyTestCase with shouldFail and other methods
                      – Built-in mocking and compatible with Java mocking
                    • Integration testing
                      – Metaprogramming allows various kinds of IOC like
© ASERT 2006-2010




                        intercepting and hooking up of components
                      – Wealth of GDK methods for Ant, Processes, Files,
                        Threads, etc. make the automating part much simpler
                    • Acceptance Testing and Generally
                      – Allows creation of English-like testing DSLs using
                        Closures, builders, metaprogramming
                      – Simpler syntax great for non hard-core testers
                      – Grapes make tests easier to share               QCON 2010 - 73
Groovy and Testing Tool Spectrum*
                                 Utilities                                                Runners
                       AllPairs, Combinations                  Native Groovy, JUnit, TestNG, Spock, EasyB,
                         Polyglot languages                      JBehave, Cucumber, Robot Framework
                        Logic programming
                         Threads, Parallel /
                                                               Web               Database              SOAP /              Other
                       Concurrency libraries
                                                              Drivers             Drivers               REST              Drivers
                        Data-driven libraries
                                                                                                       Drivers
                        Networking libraries                WebTest               DbUnit                                   FEST
© ASERT 2006-2010




                          XML Processing                                                            GroovyWS
                                                           WebDriver            DataSets                                   Email
                          Read/write files /
                                                           JWebUnit              SqlUnit            XML-RPC                 FTP
                        Excel / Word / CSV
                         Reporting, Logging                 Tellurium           groovy.sql             CXF                AntUnit
                                                            Selenium               JPA                Axis2               Telnet
                                                            HtmlUnit               JDO               JAX-WS                SSH
                                Tools                         Watij              BigTable            JAX-RS                Exec
                       iTest2, SoapUI, Twist,              HttpBuilder            JDBC
                         IDEs, JMeter, Text                Cyberneko
                         editors, Recorders,
                        Sahi, Build Tools, CI

                    * Tools/libraries/frameworks don't always neatly fall into one category – still useful conceptually    QCON 2010 - 74
HtmlUnit
                    • 100% Java-based headless browser emulator
                      – Can test any Web site: Java, .Net, PHP, Rails, ...
                    • Open Source
                      –   Apache 2 license
                      –   Hosted at SourceForge
                      –   7 committers (3 very active)
                      –
© ASERT 2006-2010




                          Very mature
                    • Useful for:
                      – Integration and acceptance testing
                      – Screen scraping, deployment automation, ...
                    • Used by other drivers:
                      – Canoo WebTest , JWebUnit , WebDriver , JSFUnit , Celerity
                    • Special features:
                      – Easy ajax mode, emulation of multiple browsers
                                                                               QCON 2010 - 75
HtmlUnit: Testing New Blog Post...
                    @Grab('net.sourceforge.htmlunit:htmlunit:2.6')
                    import com.gargoylesoftware.htmlunit.WebClient

                    def client = new WebClient()
                    def page = client.getPage('http://localhost:8080/postForm')
                    // check page title
                    assert 'Welcome to SimpBlog' == page.titleText
© ASERT 2006-2010




                    // fill in blog entry and post it
                    def form = page.getFormByName('post')
                    form.getInputByName('title').
                        setValueAttribute('Bart was here (and so was HtmlUnit)')
                    form.getSelectByName('category').getOptions().find{
                        it.text == 'Home' }.setSelected(true)
                    form.getTextAreaByName('content').setText('Cowabunga Dude!')
                    def result = form.getInputByName('btnPost').click()

                    ...

                                                                         QCON 2010 - 76
...HtmlUnit: Testing New Blog Post

                    ...

                    // check blog post details
                    assert result.getElementsByTagName('h1').item(0).
                        textContent.matches('Post.*: Bart was here.*')
                    def h3headings = result.getElementsByTagName('h3')
© ASERT 2006-2010




                    assert h3headings.item(1).textContent == 'Category: Home'
                    assert h3headings.item(2).textContent == 'Author: Bart'

                    // expecting:
                    // <table><tr><td><p>Cowabunga Dude!</p></td></tr></table>
                    def cell = result.getByXPath('//TABLE//TR/TD')[0]
                    def para = cell.getFirstChild()
                    assert para.textContent == 'Cowabunga Dude!'




                                                                         QCON 2010 - 77
WebTest testing Web Sites
                    def ant = new AntBuilder()

                    def webtest_home = System.properties.'webtest.home'

                    ant.taskdef(resource:'webtest.taskdef') {
                      classpath {
                           pathelement(location:"$webtest_home/lib")
                           fileset(dir:"$webtest_home/lib", includes:"**/*.jar")
                      }
                    }
© ASERT 2006-2010




                    def config_map = [:]
                    ['protocol','host','port','basepath','resultfile',
                    'resultpath', 'summary', 'saveresponse','defaultpropertytype'].each {
                       config_map[it] = System.properties['webtest.'+it]
                    }

                    ant.testSpec(name:'groovy: Test Groovy Scripting at creation time') {
                      config(config_map)
                      steps {
                         invoke(url:'linkpage.html')
                         for (i in 1..10) {
                            verifyText(description:"verify number ${i} is on pages", text:"${i}")
                         }
                      }
                    }
                                                                                                    QCON 2010 - 78
WebTest testing Emails
                    def ant = new AntBuilder()

                    def webtest_home = System.properties.'webtest.home'

                    ant.taskdef(resource:'webtest.taskdef'){
                      classpath(){
                         pathelement(location:"$webtest_home/lib")
                         fileset(dir:"$webtest_home/lib", includes:"**/*.jar")
                      }
                    }
© ASERT 2006-2010




                    ant.testSpec(name:'Email Test'){
                      steps {
                         emailSetConfig(server:'localhost', password:'password',
                            username:'devteam@mycompany.org', type:'pop3')
                         emailStoreMessageId(subject:'/Build notification/',
                            property:'msg')
                         emailStoreHeader(property:'subject',
                            messageId:'#{msg}', headerName:'Subject')
                         groovy('''def subject = step.webtestProperties.subject
                            assert subject.startsWith('Build notification')''')
                         emailMessageContentFilter(messageId:'#{msg}')
                         verifyText(text:'Failed build')
                      }
                    }
                                                                                   QCON 2010 - 79
Spock Testing Framework...
© ASERT 2006-2010




                                                 QCON 2010 - 80
...Spock Testing Framework
                    • Testing framework for Java and Groovy
                    • Highly expressive specification language
                       – No assertion API
                       – No record &
                         replay          @Speck
                         mocking API     @RunWith(Sputnik)
                       – No              class PublisherSubscriberSpeck {
                         superfluous       def "events are received by all subscribers"() {
© ASERT 2006-2010




                         annotations         def pub = new Publisher()
                       – Meaningful          def sub1 = Mock(Subscriber)
                         assert error        def sub2 = Mock(Subscriber)
                         messages            pub.subscribers << sub1 << sub2

                                                 when:
                                                 pub.send("event")

                                                 then:
                       – Extensible              1 * sub1.receive("event")
                       – Compatible              1 * sub2.receive("event")
                         with JUnit          }
                         reportingwise   }
                                                                                   QCON 2010 - 81
Spock Example...
                    import com.gargoylesoftware.htmlunit.WebClient
                    import spock.lang.*
                    import org.junit.runner.RunWith

                    @Speck ()
                    @RunWith (Sputnik)
                    class TestSimpBlogSpock {
                      def page, subheadings, para, form, result

                     @Unroll("When #author posts a #category blog with content '#content' it shoul
© ASERT 2006-2010




                     def "when creating a new blog entry"() {
                       given:
                         page = new WebClient().getPage('http://localhost:8080/postForm')
                         form = page.getFormByName('post')

                          when:
                            form.getInputByName('title').setValueAttribute("$author was here (and so
                            form.getSelectByName('category').getOptions().find { it.text == category
                            form.getSelectByName('author').getOptions().find { it.text == author }.se
                            form.getTextAreaByName('content').setText(content)
                            result = form.getInputByName('btnPost').click()
                            subheadings = result.getElementsByTagName('h3')
                            para = result.getByXPath('//TABLE//TR/TD/P')[0]
                    ...
                                                                                          QCON 2010 - 82
...Spock Example
                    ...
                      then:
                        page.titleText == 'Welcome to SimpBlog'
                        result.getElementsByTagName('h1').item(0).textContent.matches("Post.*: $auth
                        subheadings.item(1).textContent == "Category: $category"
                        subheadings.item(2).textContent == "Author: $author"

                        and:
                                                                          // Optional use of 'and:'
                          para.textContent == content
© ASERT 2006-2010




                        where:
                          author   << ['Bart', 'Homer', 'Lisa']
                          category << ['Home', 'Work', 'Food']
                          content << ['foo', 'bar', 'baz']
                        }
                    }




                                                                                             QCON 2010 - 83
EasyB
                    • Description: BDD, Rspec-like testing library
                    narrative 'segment flown', {
                        as_a 'frequent flyer'
                        i_want 'to accrue rewards points for every segment I fly'
                        so_that 'I can receive free flights for my dedication to the airline'
                    }

                    scenario 'segment flown', {
                        given 'a frequent flyer with a rewards balance of 1500 points'
© ASERT 2006-2010




                        when 'that flyer completes a segment worth 500 points'
                        then 'that flyer has a new rewards balance of 2000 points'
                    }

                    scenario 'segment flown', {
                         given 'a frequent flyer with a rewards balance of 1500 points', {
                             flyer = new FrequentFlyer(1500)
                         }
                         when 'that flyer completes a segment worth 500 points', {
                             flyer.fly(new Segment(500))
                         }
                         then 'that flyer has a new rewards balance of 2000 points', {
                             flyer.pointsBalance.shouldBe 2000
                         }
                     }                                                                  QCON 2010 - 84
EasyB Example ...
                    • When run will be marked as pending
                      – perfect for ATDD

                      scenario "Bart posts a new blog entry", {
                          given "we are on the create blog entry page"
                          when "I have entered 'Bart was here' as the title"
                          and "I have entered 'Cowabunga Dude!' into the content"
                          and "I have selected 'Home' as the category"
© ASERT 2006-2010




                          and "I have selected 'Bart' as the author"
                          and "I click the 'Create Post' button"
                          then "I expect the entry to be posted"
                      }




                                                                                    QCON 2010 - 85
...EasyB Example...
                    description "Post Blog Entry Feature"

                    narrative "for feature", {
                        as_a "Blogger"
                        i_want "to be able to post a blog"
                        so_that "I can keep others informed"
                    }

                    before "posting blog", {
                        given "we are on the create blog entry page", {
© ASERT 2006-2010




                            webClient = new com.gargoylesoftware.htmlunit.WebClient()
                            page = webClient.getPage('http://localhost:8080/postForm')
                        }
                    }

                    scenario "Bart was here blog", {

                          when "I have entered 'Bart was here' as the title", {
                              form = page.getFormByName('post')
                              form.getInputByName('title').setValueAttribute(
                                  'Bart was here (and so was EasyB)')
                          }

                    ...
                                                                                         QCON 2010 - 86
...EasyB Example...
                    ...
                      and "I have entered 'Cowabunga Dude!' into the content", {
                        form.getTextAreaByName('content').setText('Cowabunga Dude!')
                      }

                        and "I have selected 'Home' as the category", {
                          form.getSelectByName('category').getOptions().find { it.text == 'Home' }.setSelected(
                        }

                        and "I click the 'Create Post' button", {
                          result = form.getInputByName('btnPost').click()
                        }
© ASERT 2006-2010




                        then "I expect the entry to be posted", {
                          // check blog post details
                          assert result.getElementsByTagName('h1').item(0).textContent.matches('Post.*: Bart wa
                          def h3headings = result.getElementsByTagName('h3')
                          assert h3headings.item(1).textContent == 'Category: Home'      // traditional style
                          h3headings.item(2).textContent.shouldBe 'Author: Bart'         // BDD style

                            // expecting: <table><tr><td><p>Cowabunga Dude!</p></td></tr></table>
                            def cell = result.getByXPath('//TABLE//TR/TD')[0]
                            def para = cell.firstChild
                            assert para.textContent == 'Cowabunga Dude!'
                            // para.shouldHave textContent: 'Cowabunga Dude!'
                        }
                    }

                                                                                                    QCON 2010 - 87
...EasyB Example...
© ASERT 2006-2010




                                          QCON 2010 - 88
...EasyB Example
                    2 scenarios (including 1 pending) executed successfully.

                     Story: simp blog initial

                      scenario Bart posts a new blog entry [PENDING]
                       given we are on the create blog entry page
                       when I have entered 'Bart was here' as the title
                       when I have entered 'Cowabunga Dude!' into the content [PENDING]
                       when I have selected 'Home' as the category [PENDING]
                       when I have selected 'Bart' as the author [PENDING]
                       when I click the 'Create Post' button [PENDING]
                       then I expect the entry to be posted [PENDING]

                     Story: simp blog                                easyb is preparing to process 2 file(s)
© ASERT 2006-2010




                     Post Blog Entry Feature                         Running simp blog initial story (SimpBlogInitialStory.groovy)
                     for feature                                     Scenarios run: 1, Failures: 0, Pending: 1, Time elapsed: 1.049 sec
                       As a Blogger                                  Running simp blog story (SimpBlogStory.groovy)
                       I want to be able to post a blog              Scenarios run: 1, Failures: 0, Pending: 0, Time elapsed: 1.356 sec
                       So that I can keep others informed
                       given we are on the create blog entry page    2 total behaviors ran (including 1 pending behavior) with no failures
                                                                     easyb execution passed
                      scenario Bart was here blog
                       when I have entered 'Bart was here' as the title
                       when I have entered 'Cowabunga Dude!' into the content
                       when I have selected 'Home' as the category
                       when I click the 'Create Post' button
                       then I expect the entry to be posted




                                                                                                                             QCON 2010 - 89
Cucumber
                                            # language: en
                    • Description           Feature: Addition
                                              In order to avoid silly mistakes
                      – Loose coupling        As a math idiot
                        between text spec     I want to be told the sum of two numbers

                        and step defns       Scenario Outline: Add two numbers
                                               Given I have entered <input_1> into the calculator
                                               And I have entered <input_2> into the calculator
                                               When I press <button>
                                               Then the stored result should be <output>

                                             Examples:
© ASERT 2006-2010




                                               | input_1   |   input_2   |   button   |   output   |
                                               | 20        |   30        |   add      |   50       |
                                               | 2         |   5         |   add      |   7        |
                                               | 0         |   40        |   add      |   40       |
                                            # language: en
                                            Feature: Division
                                              In order to avoid silly mistakes
                                              Cashiers must be able to calculate a fraction

                                              Scenario: Regular numbers
                                                Given I have entered 3 into the calculator
                                                And I have entered 2 into the calculator
                                                When I press divide
                                                Then the stored result should be 1.5
                                                                                                       QCON 2010 - 90
Cucumber Example...


                    # language: en
                    @newpost
                    Feature: New Blog Post
                      In order to create a new blog entry
                      Bloggers should be able to select their name and category and enter text
© ASERT 2006-2010




                     Scenario: New Posting
                       Given we are on the create blog entry page
                       When I have entered "Bart was here" as the title
                       And I have entered "Cowabunga Dude!" as the content
                       And I have selected "Home" from the "category" dropdown
                       And I have selected "Bart" from the "author" dropdown
                       And I click the 'Create Post' button
                       Then I should see a heading message matching "Post.*: Bart was here.*"




                                                                                         QCON 2010 - 91
...Cucumber Example...
© ASERT 2006-2010




                                             QCON 2010 - 92
...Cucumber Example
                    import com.gargoylesoftware.htmlunit.WebClient
                    this.metaClass.mixin(cuke4duke.GroovyDsl)

                    Given ~/we are on the create blog entry page/, { ->
                        page = new WebClient().getPage('http://localhost:8080/postForm')
                    }

                    When(~/I have entered "(.*)" as the title/) {String title ->
                        form = page.getFormByName('post')
                        form.getInputByName('title').setValueAttribute(title + ' (and so was Cucumber)')
                    }

                    When(~'I have entered "(.*)" as the content') {String content ->
© ASERT 2006-2010




                        form.getTextAreaByName('content').setText(content)
                    }

                    When(~'I have selected "(.*)" from the "(.*)" dropdown') {String option, String name ->
                        form.getSelectByName(name).getOptions().find {
                            it.text == option }.setSelected(true)
                    }

                    When(~"I click the 'Create Post' button") { ->
                        result = form.getInputByName('btnPost').click()
                    }

                    Then(~'I should see a heading message matching "(.*)"') {String pattern ->
                    // ensureThat result.getElementsByTagName('h1').item(0).textContent.matches(pattern)
                        assert result.getElementsByTagName('h1').item(0).textContent.matches(pattern)
                    }
                                                                                                 QCON 2010 - 93
Cucumber Data Driven Example...

                    # language: en
                    @newpost
                    Feature: New Blog Post
                      In order to create a new blog entry
                      Bloggers should be able to select their name and category and enter text

                     Scenario Outline: New Posting
                       Given we are on the create blog entry page
© ASERT 2006-2010




                       When I have entered "<title>" as the title
                       And I have entered "<content>" as the content
                       And I have selected "<category>" from the "category" dropdown
                       And I have selected "<author>" from the "author" dropdown
                       And I click the 'Create Post' button
                       Then I should see a heading message matching "Post.*: <title>.*"

                     Examples:
                       | title   | content   | category   |   author   |
                       | Title 1 | Content 1 | Home       |   Bart     |
                       | Title 2 | Content 2 | Work       |   Homer    |
                       | Title 3 | Content 3 | Food       |   Marge    |



                                                                                       QCON 2010 - 94
...Cucumber Data Driven Example
© ASERT 2006-2010




                                                  QCON 2010 - 95
JBehave
                    • Description
                      – Behaviour-driven development in Java
                         • Also works out of the box for Groovy
                      – Behavior scenarios written in text
                         • Use the words Given, When, Then and And.
                      – Mapped using regular expressions and annotations
© ASERT 2006-2010




                        to step methods
                      – Web Runner available for non-technical users to
                        easily run tests
                      – Hooks to Selenium available in JBehave Web
                         • Other Java libraries (e.g. HtmlUnit) easy to use too
                      – Supports parameter converters
                         • Getting 'String' parameters into appropriate Object values
                      – Supports a 'StepDoc' function
                         • For listing available scenario clauses
                                                                                  QCON 2010 - 96
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features
Groovy Power Features

Contenu connexe

Tendances

Jaoo Michael Neale 09
Jaoo Michael Neale 09Jaoo Michael Neale 09
Jaoo Michael Neale 09Michael Neale
 
Server Side JavaScript on the JVM - Project Avatar - QCon London March 2014
Server Side JavaScript on the JVM - Project Avatar - QCon London March 2014Server Side JavaScript on the JVM - Project Avatar - QCon London March 2014
Server Side JavaScript on the JVM - Project Avatar - QCon London March 2014David Delabassee
 
Building Content Applications with JCR and OSGi
Building Content Applications with JCR and OSGiBuilding Content Applications with JCR and OSGi
Building Content Applications with JCR and OSGiCédric Hüsler
 
Ror Seminar With agilebd.org on 23 Jan09
Ror Seminar With agilebd.org on 23 Jan09Ror Seminar With agilebd.org on 23 Jan09
Ror Seminar With agilebd.org on 23 Jan09Shaer Hassan
 
Powering the Next Generation Services with Java Platform - Spark IT 2010
Powering the Next Generation Services with Java Platform - Spark IT 2010Powering the Next Generation Services with Java Platform - Spark IT 2010
Powering the Next Generation Services with Java Platform - Spark IT 2010Arun Gupta
 
Ruby on Rails Training - Module 1
Ruby on Rails Training - Module 1Ruby on Rails Training - Module 1
Ruby on Rails Training - Module 1Mark Menard
 
Security Goodness with Ruby on Rails
Security Goodness with Ruby on RailsSecurity Goodness with Ruby on Rails
Security Goodness with Ruby on RailsSource Conference
 
Ruby on Rails 101 - Presentation Slides for a Five Day Introductory Course
Ruby on Rails 101 - Presentation Slides for a Five Day Introductory CourseRuby on Rails 101 - Presentation Slides for a Five Day Introductory Course
Ruby on Rails 101 - Presentation Slides for a Five Day Introductory Coursepeter_marklund
 
O que há de novo no Rails 3
O que há de novo no Rails 3O que há de novo no Rails 3
O que há de novo no Rails 3Hugo Baraúna
 
Dynamic Languages & Web Frameworks in GlassFish
Dynamic Languages & Web Frameworks in GlassFishDynamic Languages & Web Frameworks in GlassFish
Dynamic Languages & Web Frameworks in GlassFishIndicThreads
 
Groovy, Transforming Language
Groovy, Transforming LanguageGroovy, Transforming Language
Groovy, Transforming LanguageUehara Junji
 
Apache camel overview dec 2011
Apache camel overview dec 2011Apache camel overview dec 2011
Apache camel overview dec 2011Marcelo Jabali
 
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
 
PECL Picks - Extensions to make your life better
PECL Picks - Extensions to make your life betterPECL Picks - Extensions to make your life better
PECL Picks - Extensions to make your life betterZendCon
 
Aloha RubyConf 2012 - JRuby
Aloha RubyConf 2012 - JRubyAloha RubyConf 2012 - JRuby
Aloha RubyConf 2012 - JRubyCharles Nutter
 
ZFConf 2012: Capistrano для деплоймента PHP-приложений (Роман Лапин)
ZFConf 2012: Capistrano для деплоймента PHP-приложений (Роман Лапин)ZFConf 2012: Capistrano для деплоймента PHP-приложений (Роман Лапин)
ZFConf 2012: Capistrano для деплоймента PHP-приложений (Роман Лапин)ZFConf Conference
 

Tendances (20)

Jaoo Michael Neale 09
Jaoo Michael Neale 09Jaoo Michael Neale 09
Jaoo Michael Neale 09
 
Server Side JavaScript on the JVM - Project Avatar - QCon London March 2014
Server Side JavaScript on the JVM - Project Avatar - QCon London March 2014Server Side JavaScript on the JVM - Project Avatar - QCon London March 2014
Server Side JavaScript on the JVM - Project Avatar - QCon London March 2014
 
Building Content Applications with JCR and OSGi
Building Content Applications with JCR and OSGiBuilding Content Applications with JCR and OSGi
Building Content Applications with JCR and OSGi
 
Ror Seminar With agilebd.org on 23 Jan09
Ror Seminar With agilebd.org on 23 Jan09Ror Seminar With agilebd.org on 23 Jan09
Ror Seminar With agilebd.org on 23 Jan09
 
Powering the Next Generation Services with Java Platform - Spark IT 2010
Powering the Next Generation Services with Java Platform - Spark IT 2010Powering the Next Generation Services with Java Platform - Spark IT 2010
Powering the Next Generation Services with Java Platform - Spark IT 2010
 
Ruby on Rails Training - Module 1
Ruby on Rails Training - Module 1Ruby on Rails Training - Module 1
Ruby on Rails Training - Module 1
 
Security Goodness with Ruby on Rails
Security Goodness with Ruby on RailsSecurity Goodness with Ruby on Rails
Security Goodness with Ruby on Rails
 
Ruby on Rails 101 - Presentation Slides for a Five Day Introductory Course
Ruby on Rails 101 - Presentation Slides for a Five Day Introductory CourseRuby on Rails 101 - Presentation Slides for a Five Day Introductory Course
Ruby on Rails 101 - Presentation Slides for a Five Day Introductory Course
 
O que há de novo no Rails 3
O que há de novo no Rails 3O que há de novo no Rails 3
O que há de novo no Rails 3
 
Dynamic Languages & Web Frameworks in GlassFish
Dynamic Languages & Web Frameworks in GlassFishDynamic Languages & Web Frameworks in GlassFish
Dynamic Languages & Web Frameworks in GlassFish
 
Groovy, Transforming Language
Groovy, Transforming LanguageGroovy, Transforming Language
Groovy, Transforming Language
 
Apache camel overview dec 2011
Apache camel overview dec 2011Apache camel overview dec 2011
Apache camel overview dec 2011
 
RubyGems 3 & 4
RubyGems 3 & 4RubyGems 3 & 4
RubyGems 3 & 4
 
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
 
Django in the Real World
Django in the Real WorldDjango in the Real World
Django in the Real World
 
PECL Picks - Extensions to make your life better
PECL Picks - Extensions to make your life betterPECL Picks - Extensions to make your life better
PECL Picks - Extensions to make your life better
 
Aloha RubyConf 2012 - JRuby
Aloha RubyConf 2012 - JRubyAloha RubyConf 2012 - JRuby
Aloha RubyConf 2012 - JRuby
 
ZFConf 2012: Capistrano для деплоймента PHP-приложений (Роман Лапин)
ZFConf 2012: Capistrano для деплоймента PHP-приложений (Роман Лапин)ZFConf 2012: Capistrano для деплоймента PHP-приложений (Роман Лапин)
ZFConf 2012: Capistrano для деплоймента PHP-приложений (Роман Лапин)
 
Workin On The Rails Road
Workin On The Rails RoadWorkin On The Rails Road
Workin On The Rails Road
 
Till Vollmer Presentation
Till Vollmer PresentationTill Vollmer Presentation
Till Vollmer Presentation
 

Similaire à Groovy Power Features

Groovy Tutorial
Groovy TutorialGroovy Tutorial
Groovy TutorialPaul King
 
RESTful Services and Distributed OSGi - 04/2009
RESTful Services and Distributed OSGi - 04/2009RESTful Services and Distributed OSGi - 04/2009
RESTful Services and Distributed OSGi - 04/2009Roland Tritsch
 
XML and Web Services with Groovy
XML and Web Services with GroovyXML and Web Services with Groovy
XML and Web Services with GroovyPaul King
 
Introducing Scalate, the Scala Template Engine
Introducing Scalate, the Scala Template EngineIntroducing Scalate, the Scala Template Engine
Introducing Scalate, the Scala Template EngineJames Strachan
 
WebSocket Perspectives and Vision for the Future
WebSocket Perspectives and Vision for the FutureWebSocket Perspectives and Vision for the Future
WebSocket Perspectives and Vision for the FutureFrank Greco
 
Comparing JVM Web Frameworks - Rich Web Experience 2010
Comparing JVM Web Frameworks - Rich Web Experience 2010Comparing JVM Web Frameworks - Rich Web Experience 2010
Comparing JVM Web Frameworks - Rich Web Experience 2010Matt Raible
 
Project Avatar (Lyon JUG & Alpes JUG - March 2014)
Project Avatar (Lyon JUG & Alpes JUG  - March 2014)Project Avatar (Lyon JUG & Alpes JUG  - March 2014)
Project Avatar (Lyon JUG & Alpes JUG - March 2014)David Delabassee
 
Java EE 7 et ensuite pourquoi pas JavaScript sur le serveur!
Java EE 7 et ensuite pourquoi pas JavaScript sur le serveur! Java EE 7 et ensuite pourquoi pas JavaScript sur le serveur!
Java EE 7 et ensuite pourquoi pas JavaScript sur le serveur! David Delabassee
 
Groovy Testing Aug2009
Groovy Testing Aug2009Groovy Testing Aug2009
Groovy Testing Aug2009guest4a266c
 
Building Next-Gen Web Applications with the Spring 3 Web Stack
Building Next-Gen Web Applications with the Spring 3 Web StackBuilding Next-Gen Web Applications with the Spring 3 Web Stack
Building Next-Gen Web Applications with the Spring 3 Web StackJeremy Grelle
 
Make the Shift from Manual to Automation with Open Source
Make the Shift from Manual to Automation with Open SourceMake the Shift from Manual to Automation with Open Source
Make the Shift from Manual to Automation with Open SourcePerfecto by Perforce
 
Construindo aplicações com HTML5, WebSockets, e Java EE 7
Construindo aplicações com HTML5, WebSockets, e Java EE 7Construindo aplicações com HTML5, WebSockets, e Java EE 7
Construindo aplicações com HTML5, WebSockets, e Java EE 7Bruno Borges
 
Mobile web me2day_seminar
Mobile web me2day_seminarMobile web me2day_seminar
Mobile web me2day_seminarSang-il Jung
 
HTML5 Overview (Silicon Valley User Group)
HTML5 Overview (Silicon Valley User Group)HTML5 Overview (Silicon Valley User Group)
HTML5 Overview (Silicon Valley User Group)robinzimmermann
 
HTML5 Real Time and WebSocket Code Lab (SFHTML5, GTUGSF)
HTML5 Real Time and WebSocket Code Lab (SFHTML5, GTUGSF)HTML5 Real Time and WebSocket Code Lab (SFHTML5, GTUGSF)
HTML5 Real Time and WebSocket Code Lab (SFHTML5, GTUGSF)Peter Lubbers
 
Jboss Application Server training-course-navi-mumbai-jboss-course-provider-na...
Jboss Application Server training-course-navi-mumbai-jboss-course-provider-na...Jboss Application Server training-course-navi-mumbai-jboss-course-provider-na...
Jboss Application Server training-course-navi-mumbai-jboss-course-provider-na...VibrantGroup
 
Groovy Testing Sep2009
Groovy Testing Sep2009Groovy Testing Sep2009
Groovy Testing Sep2009Paul King
 
HTML5 Websockets and Java - Arun Gupta
HTML5 Websockets and Java - Arun GuptaHTML5 Websockets and Java - Arun Gupta
HTML5 Websockets and Java - Arun GuptaJAX London
 
make builds groovy
make builds groovymake builds groovy
make builds groovyguest88884d
 

Similaire à Groovy Power Features (20)

Groovy Tutorial
Groovy TutorialGroovy Tutorial
Groovy Tutorial
 
RESTful Services and Distributed OSGi - 04/2009
RESTful Services and Distributed OSGi - 04/2009RESTful Services and Distributed OSGi - 04/2009
RESTful Services and Distributed OSGi - 04/2009
 
XML and Web Services with Groovy
XML and Web Services with GroovyXML and Web Services with Groovy
XML and Web Services with Groovy
 
Introducing Scalate, the Scala Template Engine
Introducing Scalate, the Scala Template EngineIntroducing Scalate, the Scala Template Engine
Introducing Scalate, the Scala Template Engine
 
WebSocket Perspectives and Vision for the Future
WebSocket Perspectives and Vision for the FutureWebSocket Perspectives and Vision for the Future
WebSocket Perspectives and Vision for the Future
 
Comparing JVM Web Frameworks - Rich Web Experience 2010
Comparing JVM Web Frameworks - Rich Web Experience 2010Comparing JVM Web Frameworks - Rich Web Experience 2010
Comparing JVM Web Frameworks - Rich Web Experience 2010
 
Project Avatar (Lyon JUG & Alpes JUG - March 2014)
Project Avatar (Lyon JUG & Alpes JUG  - March 2014)Project Avatar (Lyon JUG & Alpes JUG  - March 2014)
Project Avatar (Lyon JUG & Alpes JUG - March 2014)
 
Java EE 7 et ensuite pourquoi pas JavaScript sur le serveur!
Java EE 7 et ensuite pourquoi pas JavaScript sur le serveur! Java EE 7 et ensuite pourquoi pas JavaScript sur le serveur!
Java EE 7 et ensuite pourquoi pas JavaScript sur le serveur!
 
Groovy Testing Aug2009
Groovy Testing Aug2009Groovy Testing Aug2009
Groovy Testing Aug2009
 
Building Next-Gen Web Applications with the Spring 3 Web Stack
Building Next-Gen Web Applications with the Spring 3 Web StackBuilding Next-Gen Web Applications with the Spring 3 Web Stack
Building Next-Gen Web Applications with the Spring 3 Web Stack
 
Make the Shift from Manual to Automation with Open Source
Make the Shift from Manual to Automation with Open SourceMake the Shift from Manual to Automation with Open Source
Make the Shift from Manual to Automation with Open Source
 
Construindo aplicações com HTML5, WebSockets, e Java EE 7
Construindo aplicações com HTML5, WebSockets, e Java EE 7Construindo aplicações com HTML5, WebSockets, e Java EE 7
Construindo aplicações com HTML5, WebSockets, e Java EE 7
 
Mobile web me2day_seminar
Mobile web me2day_seminarMobile web me2day_seminar
Mobile web me2day_seminar
 
HTML5 Overview (Silicon Valley User Group)
HTML5 Overview (Silicon Valley User Group)HTML5 Overview (Silicon Valley User Group)
HTML5 Overview (Silicon Valley User Group)
 
HTML5 Real Time and WebSocket Code Lab (SFHTML5, GTUGSF)
HTML5 Real Time and WebSocket Code Lab (SFHTML5, GTUGSF)HTML5 Real Time and WebSocket Code Lab (SFHTML5, GTUGSF)
HTML5 Real Time and WebSocket Code Lab (SFHTML5, GTUGSF)
 
Jboss Application Server training-course-navi-mumbai-jboss-course-provider-na...
Jboss Application Server training-course-navi-mumbai-jboss-course-provider-na...Jboss Application Server training-course-navi-mumbai-jboss-course-provider-na...
Jboss Application Server training-course-navi-mumbai-jboss-course-provider-na...
 
Groovy Testing Sep2009
Groovy Testing Sep2009Groovy Testing Sep2009
Groovy Testing Sep2009
 
Websocket 1.0
Websocket 1.0Websocket 1.0
Websocket 1.0
 
HTML5 Websockets and Java - Arun Gupta
HTML5 Websockets and Java - Arun GuptaHTML5 Websockets and Java - Arun Gupta
HTML5 Websockets and Java - Arun Gupta
 
make builds groovy
make builds groovymake builds groovy
make builds groovy
 

Plus de 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
 
concurrency gpars
concurrency gparsconcurrency gpars
concurrency gparsPaul King
 
tictactoe groovy
tictactoe groovytictactoe groovy
tictactoe groovyPaul King
 
groovy rules
groovy rulesgroovy rules
groovy rulesPaul 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
 
concurrency with GPars
concurrency with GParsconcurrency with GPars
concurrency with GParsPaul King
 
Atlassian Groovy Plugins
Atlassian Groovy PluginsAtlassian Groovy Plugins
Atlassian Groovy PluginsPaul 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
 
Make Your Testing Groovy
Make Your Testing GroovyMake Your Testing Groovy
Make Your Testing GroovyPaul 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
 
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...Paul King
 

Plus de Paul King (18)

awesome groovy
awesome groovyawesome groovy
awesome groovy
 
groovy databases
groovy databasesgroovy databases
groovy databases
 
groovy transforms
groovy transformsgroovy transforms
groovy transforms
 
concurrency gpars
concurrency gparsconcurrency gpars
concurrency gpars
 
tictactoe groovy
tictactoe groovytictactoe groovy
tictactoe groovy
 
groovy rules
groovy rulesgroovy rules
groovy rules
 
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
 
concurrency with GPars
concurrency with GParsconcurrency with GPars
concurrency with GPars
 
GroovyDSLs
GroovyDSLsGroovyDSLs
GroovyDSLs
 
Atlassian Groovy Plugins
Atlassian Groovy PluginsAtlassian Groovy Plugins
Atlassian Groovy Plugins
 
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
 
Make Your Testing Groovy
Make Your Testing GroovyMake Your Testing Groovy
Make Your Testing Groovy
 
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 ...
 
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
 

Dernier

Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...gurkirankumar98700
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Google AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGGoogle AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGSujit Pal
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 

Dernier (20)

Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Google AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGGoogle AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAG
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 

Groovy Power Features

  • 1. © ASERT 2006-2010 Groovy Power Features! Dr Paul King paulk@asert.com.au @paulk_asert ASERT, Australia
  • 2. Topics Groovy Intro • Leveraging the language • Use and abuse of Design Patterns • Web Services • Writing DSLs © ASERT 2006-2010 • Groovy Testing • Polyglot Groovy • Parallel Processing • Enterprise Groovy • More Info QCON 2010 - 2
  • 3. What is Groovy? • “Groovy is like a super version of Java. It can leverage Java's enterprise capabilities but also has cool productivity features like closures, DSL support, builders and dynamic typing.” © ASERT 2006-2010 Groovy = Java – boiler plate code + mostly dynamic typing + closures + domain specific languages + builders + metaprogramming + GDK library QCON 2010 - 3
  • 4. Groovy Goodies Overview • Fully object oriented • Closures: reusable and assignable pieces of code • Operators can be • GPath: efficient overloaded © ASERT 2006-2010 object navigation • Multimethods • GroovyBeans • Literal declaration for • grep and switch lists (arrays), maps, ranges and regular • Templates, builder, expressions swing, Ant, markup, XML, SQL, XML-RPC, Scriptom, Grails, tests, Mocks QCON 2010 - 4
  • 5. Growing Acceptance … A slow and steady start but now gaining in momentum, maturity and mindshare Now free
  • 6. … Growing Acceptance … © ASERT 2006-2010 QCON 2010 - 6
  • 7. … Growing Acceptance … © ASERT 2006-2010 Groovy and Grails downloads: 70-90K per month and growing QCON 2010 - 7
  • 8. … Growing Acceptance … © ASERT 2006-2010 Source: http://www.micropoll.com/akira/mpresult/501697-116746 Source: http://www.grailspodcast.com/ QCON 2010 - 8
  • 9. … Growing Acceptance … © ASERT 2006-2010 http://www.jroller.com/scolebourne/entry/devoxx_2008_whiteboard_votes http://www.java.net QCON 2010 - 9
  • 10. … Growing Acceptance … What alternative JVM language are you using or intending to use © ASERT 2006-2010 http://www.leonardoborges.com/writings QCON 2010 - 10
  • 11. … Growing Acceptance … © ASERT 2006-2010 http://it-republik.de/jaxenter/quickvote/results/1/poll/44 (translated using http://babelfish.yahoo.com) QCON 2010 - 11
  • 12. … Growing Acceptance … © ASERT 2006-2010 http://pollpigeon.com/jsf-grails-wicket/r/25665/ QCON 2010 - 12
  • 13. … Growing Acceptance © ASERT 2006-2010 QCON 2010 - 13
  • 14. The Landscape of JVM Languages mostly dynamic typing © ASERT 2006-2010 Dynamic features call for dynamic types Java bytecode calls for static types The terms “Java Virtual Machine” and “JVM” mean a Virtual Machine for the Java™ platform. QCON 2010 - 14
  • 15. Groovy Starter System.out.println("Hello, World!"); // optional semicolon, println 'Hello, World!' // System.out, brackets, // main() method, class defn def name = 'Guillaume' // dynamic typing println "$name, I'll get the car." // GString String longer = """${name}, the car is in the next row.""" // multi-line string © ASERT 2006-2010 // with static typing assert 0.5 == 1/2 // BigDecimal equals() def printSize(obj) { // optional duck typing print obj?.size() // safe dereferencing } def pets = ['ant', 'bee', 'cat'] // native list syntax pets.each { pet -> // closure support assert pet < 'dog' // overloading '<' on String } // or: for (pet in pets)... QCON 2010 - 15
  • 16. A Better Java... import java.util.List; import java.util.ArrayList; class Erase { private List removeLongerThan(List strings, int length) { This code List result = new ArrayList(); for (int i = 0; i < strings.size(); i++) { is valid String s = (String) strings.get(i); Java and if (s.length() <= length) { result.add(s); valid Groovy } } © ASERT 2006-2010 return result; } public static void main(String[] args) { List names = new ArrayList(); names.add("Ted"); names.add("Fred"); names.add("Jed"); names.add("Ned"); System.out.println(names); Based on an Erase e = new Erase(); example by List shortNames = e.removeLongerThan(names, 3); Jim Weirich System.out.println(shortNames.size()); for (int i = 0; i < shortNames.size(); i++) { & Ted Leung String s = (String) shortNames.get(i); System.out.println(s); } } } QCON 2010 - 16
  • 17. ...A Better Java... import java.util.List; import java.util.ArrayList; class Erase { private List removeLongerThan(List strings, int length) { Do the List result = new ArrayList(); for (int i = 0; i < strings.size(); i++) { semicolons String s = (String) strings.get(i); add anything? if (s.length() <= length) { result.add(s); And shouldn‟t } } we us more © ASERT 2006-2010 } return result; modern list public static void main(String[] args) { notation? List names = new ArrayList(); names.add("Ted"); names.add("Fred"); Why not names.add("Jed"); names.add("Ned"); System.out.println(names); import common Erase e = new Erase(); libraries? List shortNames = e.removeLongerThan(names, 3); System.out.println(shortNames.size()); for (int i = 0; i < shortNames.size(); i++) { String s = (String) shortNames.get(i); System.out.println(s); } } } QCON 2010 - 17
  • 18. ...A Better Java... class Erase { private List removeLongerThan(List strings, int length) { List result = new ArrayList() for (String s in strings) { if (s.length() <= length) { result.add(s) } } return result } public static void main(String[] args) { © ASERT 2006-2010 List names = new ArrayList() names.add("Ted"); names.add("Fred") names.add("Jed"); names.add("Ned") System.out.println(names) Erase e = new Erase() List shortNames = e.removeLongerThan(names, 3) System.out.println(shortNames.size()) for (String s in shortNames) { System.out.println(s) } } } QCON 2010 - 18
  • 19. ...A Better Java... class Erase { private List removeLongerThan(List strings, int length) { List result = new ArrayList() for (String s in strings) { if (s.length() <= length) { result.add(s) Do we need } the static types? } return result Must we always } have a main public static void main(String[] args) { method and © ASERT 2006-2010 List names = new ArrayList() names.add("Ted"); names.add("Fred") class definition? names.add("Jed"); names.add("Ned") System.out.println(names) How about Erase e = new Erase() List shortNames = e.removeLongerThan(names, 3) improved System.out.println(shortNames.size()) consistency? for (String s in shortNames) { System.out.println(s) } } } QCON 2010 - 19
  • 20. ...A Better Java... def removeLongerThan(strings, length) { def result = new ArrayList() for (s in strings) { if (s.size() <= length) { result.add(s) } } return result } © ASERT 2006-2010 names = new ArrayList() names.add("Ted") names.add("Fred") names.add("Jed") names.add("Ned") System.out.println(names) shortNames = removeLongerThan(names, 3) System.out.println(shortNames.size()) for (s in shortNames) { System.out.println(s) } QCON 2010 - 20
  • 21. ...A Better Java... def removeLongerThan(strings, length) { def result = new ArrayList() for (s in strings) { if (s.size() <= length) { result.add(s) Shouldn‟t we } } have special return result notation for lists? } And special © ASERT 2006-2010 names = new ArrayList() facilities for names.add("Ted") names.add("Fred") list processing? names.add("Jed") Is „return‟ names.add("Ned") System.out.println(names) needed at end? shortNames = removeLongerThan(names, 3) System.out.println(shortNames.size()) for (s in shortNames) { System.out.println(s) } QCON 2010 - 21
  • 22. ...A Better Java... def removeLongerThan(strings, length) { strings.findAll{ it.size() <= length } } names = ["Ted", "Fred", "Jed", "Ned"] System.out.println(names) shortNames = removeLongerThan(names, 3) System.out.println(shortNames.size()) shortNames.each{ System.out.println(s) } © ASERT 2006-2010 QCON 2010 - 22
  • 23. ...A Better Java... def removeLongerThan(strings, length) { strings.findAll{ it.size() <= length } } Is the method names = ["Ted", "Fred", "Jed", "Ned"] now needed? System.out.println(names) shortNames = removeLongerThan(names, 3) Easier ways to System.out.println(shortNames.size()) use common shortNames.each{ System.out.println(s) } methods? © ASERT 2006-2010 Are brackets required here? QCON 2010 - 23
  • 24. ...A Better Java... names = ["Ted", "Fred", "Jed", "Ned"] println names shortNames = names.findAll{ it.size() <= 3 } println shortNames.size() shortNames.each{ println it } © ASERT 2006-2010 QCON 2010 - 24
  • 25. ...A Better Java names = ["Ted", "Fred", "Jed", "Ned"] println names shortNames = names.findAll{ it.size() <= 3 } println shortNames.size() shortNames.each{ println it } © ASERT 2006-2010 [Ted, Fred, Jed, Ned] 3 Ted Jed Ned QCON 2010 - 25
  • 26. Topics • Groovy Intro Leveraging the language • Use and abuse of Design Patterns • Web Services • Writing DSLs © ASERT 2006-2010 • Groovy Testing • Polyglot Groovy • Parallel Processing • Enterprise Groovy • More Info QCON 2010 - 26
  • 27. Better Control Structures: Switch switch (10) { case 0 : assert false ; break case 0..9 : assert false ; break case [8,9,11] : assert false ; break case Float : assert false ; break case {it%3 == 0} : assert false ; break case ~/../ : assert true ; break © ASERT 2006-2010 default : assert false ; break } • Extensible – Implement your own isCase() method QCON 2010 - 27
  • 28. Better Control Structures: Switch – Custom isCase WARNING: enum Color { Advanced yellow, orange, purple Topic! def isCase(thing) { thing.color == this } } import static Color.* class Banana { def color = yellow } class Orange { def color = orange } class Grape { def color = purple } © ASERT 2006-2010 fruits = [new Banana(), new Orange(), new Grape()] fruits.each { println inspectFruit(it) } def inspectFruit(f) { switch (f) { case yellow: return 'Found something yellow' case orange: return 'Found something orange' default: return 'Unknown color' } } Found something yellow Found something orange Unknown color QCON 2010 - 28
  • 29. Better Control Structures: Switch – Custom isCase enum Color { yellow, orange, purple } import static Color.* class Banana { def color = yellow } class Orange { def color = orange } class Grape { def color = purple } fruits = [new Banana(), new Orange(), new Grape()] fruits.each { println inspectFruit(it) } def inspectFruit(f) { © ASERT 2006-2010 switch (f.color) { case [yellow, orange]: return "Found something $f.color" default: return 'Unknown color' } } Found something yellow Found something orange Unknown color QCON 2010 - 29
  • 30. Better Control Structures: Switch – Custom isCase enum Color { WARNING: yellow, orange, purple Advanced Topic! def isCase(thing) { thing?.hasProperty('color') && thing.color == this } } enum State { peeled, unpeeled def isCase(thing) { try { © ASERT 2006-2010 return thing.color == this } catch (MissingPropertyException) { return false } } import static Color.* import static State.* class Banana { def color = yellow; def state = peeled } class Orange { def color = orange } class Grape { def state = peeled } ... QCON 2010 - 30
  • 31. Better Control Structures: Switch – Custom isCase WARNING: ... Advanced Topic! fruits = [new Banana(), new Orange(), new Grape()] fruits.each { println inspectFruit(it) } def inspectFruit(f) { def yellowAndPeeled = { yellow.isCase(it) && peeled.isCase(it) } switch (f) { © ASERT 2006-2010 case yellowAndPeeled: return 'Possibly found a banana split' case yellow: return 'Found something yellow' case peeled: return 'Found something peeled' default: return 'No comment' } Possibly found a banana split } No comment Found something peeled QCON 2010 - 31
  • 32. Better Control Structures: Switch Poker… hand1 hand2 8C TS KC 9H 4S 7D 2S 5D 3S AC suits = 'SHDC' ranks = '23456789TJQKA' suit = { String card -> suits.indexOf(card[1]) } rank = { String card -> ranks.indexOf(card[0]) } rankSizes = { List cards -> © ASERT 2006-2010 cards.groupBy(rank).collect{ k, v -> v.size() }.sort() } rankValues = { List cards -> cards.collect{ rank(it) }.sort() } // ... println rankSizes(["7S", "7H", "2H", "7D", "AH"]) // => [1, 1, 3] QCON 2010 - 32
  • 33. …Better Control Structures: Switch Poker… // ... flush = { List cards -> cards.groupBy(suit).size() == 1 } straight = { def v = rankValues(it); v == v[0]..v[0]+4 } straightFlush = { List cards -> straight(cards) && flush(cards) } © ASERT 2006-2010 fourOfAKind = { List cards -> rankSizes(cards) == [1, 4] } fullHouse = { List cards -> rankSizes(cards) == [2, 3] } threeOfAKind = { List cards -> rankSizes(cards) == [1, 1, 3] } twoPair = { List cards -> rankSizes(cards) == [1, 2, 2] } pair = { List cards -> rankSizes(cards) == [1, 1, 1, 2] } // ... QCON 2010 - 33
  • 34. … Better Control Structures: Switch Poker // ... def rankHand(List cards) { switch (cards) { case straightFlush : return 9 case fourOfAKind : return 8 case fullHouse : return 7 case flush : return 6 © ASERT 2006-2010 case straight : return 5 case threeOfAKind : return 4 case twoPair : return 3 case pair : return 2 default : return 1 } } // ... QCON 2010 - 34
  • 35. Topics • Groovy Intro • Leveraging the language Use and abuse of Design Patterns • Web Services • Writing DSLs © ASERT 2006-2010 • Groovy Testing • Polyglot Groovy • Parallel Processing • Enterprise Groovy • More Info QCON 2010 - 35
  • 36. Grapes / Grab // Google Collections example import com.google.common.collect.HashBiMap @Grab(group='com.google.collections', module='google-collections', version='1.0-rc2') © ASERT 2006-2010 def getFruit() { [ grape:'purple', lemon:'yellow', orange:'orange' ] as HashBiMap } assert fruit.lemon == 'yellow' assert fruit.inverse().yellow == 'lemon' QCON 2010 - 36
  • 37. Better Design Patterns: Immutable... • Java Immutable Class – As per Joshua Bloch // ... @Override Effective Java public boolean equals(Object obj) { if (this == obj) public final class Punter { return true; private final String first; if (obj == null) private final String last; return false; if (getClass() != obj.getClass()) public String getFirst() { return false; return first; Punter other = (Punter) obj; } if (first == null) { © ASERT 2006-2010 if (other.first != null) public String getLast() { return false; return last; } else if (!first.equals(other.first)) } return false; 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; } } // ... QCON 2010 - 37
  • 38. ...Better Design Patterns: Immutable... • Java Immutable Class boilerplate – As per Joshua Bloch // ... @Override Effective Java public boolean equals(Object obj) { if (this == obj) public final class Punter { return true; private final String first; if (obj == null) private final String last; return false; if (getClass() != obj.getClass()) public String getFirst() { return false; return first; Punter other = (Punter) obj; } if (first == null) { © ASERT 2006-2010 if (other.first != null) public String getLast() { return false; return last; } else if (!first.equals(other.first)) } return false; 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; } } // ... QCON 2010 - 38
  • 39. ...Better Design Patterns: Immutable @Immutable class Punter { String first, last © ASERT 2006-2010 } QCON 2010 - 39
  • 40. Better Design Patterns: Singleton class Calculator { def total = 0 def add(a, b) { total++; a + b } } def INSTANCE = new Calculator() Calculator.metaClass.constructor = { -> INSTANCE } © ASERT 2006-2010 def c1 = new Calculator() def c2 = new Calculator() @Singleton(lazy=true) assert c1.add(1, 2) == 3 class X { assert c2.add(3, 4) == 7 def getHello () { "Hello, World!" assert c1.is(c2) } assert [c1, c2].total == [2, 2] } println X.instance.hello QCON 2010 - 40
  • 41. Better Design Patterns: Delegate… public Date getWhen() { import java.util.Date; return when; } public class Event { private String title; public void setWhen(Date when) { private String url; this.when = when; private Date when; } public String getUrl() { public boolean before(Date other) { return url; return when.before(other); } © ASERT 2006-2010 } public void setUrl(String url) { public void setTime(long time) { 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); } } // ... // ... QCON 2010 - 41
  • 42. …Better Design Patterns: Delegate… public Date getWhen() { import java.util.Date; return when; boilerplate } public class Event { private String title; public void setWhen(Date when) { private String url; this.when = when; private Date when; } public String getUrl() { public boolean before(Date other) { return url; return when.before(other); } © ASERT 2006-2010 } public void setUrl(String url) { public void setTime(long time) { 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); } } // ... // ... QCON 2010 - 42
  • 43. …Better Design Patterns: Delegate class Event { String title, url @Delegate Date when } © ASERT 2006-2010 def gr8conf = new Event(title: "GR8 Conference", 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) QCON 2010 - 43
  • 44. Topics • Groovy Intro • Leveraging the language • Use and abuse of Design Patterns Web Services • Writing DSLs © ASERT 2006-2010 • Groovy Testing • Polyglot Groovy • Parallel Processing • Enterprise Groovy • More Info QCON 2010 - 44
  • 45. SOAP Client and Server class MathService { double add(double a, double b) { a + b } double square(double c) { c * c } } © ASERT 2006-2010 import groovy.net.soap.SoapServer def server = new SoapServer('localhost', 6789) server.setNode('MathService') server.start() import groovy.net.soap.SoapClient def math = new SoapClient('http://localhost:6789/MathServiceInterface?wsdl') assert math.add(1.0, 2.0) == 3.0 assert math.square(3.0) == 9.0 QCON 2010 - 45
  • 46. Better Testing: SoapUI • Tool for testing Web Services has a built- in Groovy editor for custom steps © ASERT 2006-2010 QCON 2010 - 46
  • 47. Topics • Groovy Intro • Leveraging the language • Use and abuse of Design Patterns • Web Services Writing DSLs © ASERT 2006-2010 • Groovy Testing • Polyglot Groovy • Parallel Processing • Enterprise Groovy • More Info QCON 2010 - 47
  • 48. Groovy DSL Features • Literal Syntax Conventions • Scripts as well as Classes & Optional Syntax • Optional Typing & Named Arguments • Type Transformations • Using With © ASERT 2006-2010 • Operator Overloading • Closures • Runtime Metaprogramming • Compile-time Metaprogramming (AST Macros) • Builders QCON 2010 - 48
  • 49. Literal Syntax Conventions • Lists – Special syntax for list literals – Additional common methods (operator overloading) def list = [3, new Date(), 'Jan'] assert list + list == list * 2 • Maps © ASERT 2006-2010 – Special syntax for map literals – Additional common methods def map = [a: 1, b: 2] assert map['a'] == 1 && map.b == 2 • Ranges – Special syntax for various kinds of ranges def letters = 'a'..'z' def numbers = 0..<10 QCON 2010 - 49
  • 50. Scripts as well as Classes & Optional Syntax • Java public class HelloJava { public static void main(String[] args) { System.out.println("Hello World"); } } © ASERT 2006-2010 • Groovy class HelloGroovy { static main(String[] args) { System.out.println("Hello World"); } } System.out.println('Hello World'); println 'Hello World' QCON 2010 - 50
  • 51. Optional Typing & Named Params • Java import java.util.Date; import java.util.HashMap; import java.util.Map; public class OptionalSyntax { public static void printDetails(Map<String, String> args) { System.out.println("Details as at: " + new Date()); String first = args.get("first"); System.out.println("First name: " + (first != null ? first : "unknown")); © ASERT 2006-2010 String last = args.get("last"); System.out.println("Last name: " + (last != null ? last : "unknown")); } public static void main(String[] args) { Map<String, String> details = new HashMap<String, String>(); details.put("first", "John"); details.put("last", "Smith"); printDetails(details); } } def printDetails(args) { println """Details as at: ${new Date()} First name: $args.first • Groovy Last name: $args.last""" } printDetails first:'John', last:'Smith' QCON 2010 - 51
  • 52. Closures • Traditional mainstream languages – Data can be stored in variables, passed around, combined in structured ways to form more complex data; code stays put where it is defined • Languages supporting closures – Data and code can be stored in variables, passed © ASERT 2006-2010 around, combined in structured ways to form more complex algorithms and data doubleNum = { num -> num * 2 } println doubleNum(3) // => 6 processThenPrint = { num, closure -> num = closure(num); println "num is $num" } processThenPrint(3, doubleNum) // => num is 6 processThenPrint(10) { it / 2 } // => num is 5 QCON 2010 - 52
  • 53. Static Imports import groovy.swing.SwingXBuilder © ASERT 2006-2010 import static java.awt.Color.* import static java.lang.Math.* def swing = new SwingXBuilder() def frame = swing.frame(size: [300, 300]) { graph(plots: [ [GREEN, {value -> sin(value)}], [BLUE, {value -> cos(value)}], [RED, {value -> tan(value)}] ]) }.show() QCON 2010 - 53
  • 54. Using '.with' Example letters = ['a', 'b', 'c'] range = 'b'..'d' letters.with { add 'd' remove 'a' } assert letters == range © ASERT 2006-2010 map = [a:10, b:4, c:7] map.with { assert (a + b) / c == 2 } QCON 2010 - 54
  • 55. Coin example... enum Coin { penny(1), nickel(5), dime(10), quarter(25) Coin(int value) { this.value = value } int value } © ASERT 2006-2010 import static Coin.* assert 2 * quarter.value + 1 * nickel.value + 2 * penny.value == 57 QCON 2010 - 55
  • 56. ...Coin example... class CoinMath { static multiply(Integer self, Coin c) { self * c.value } } use (CoinMath) { © ASERT 2006-2010 assert 2 * quarter + 1 * nickel + 2 * penny == 57 } // EMC equivalent Integer.metaClass.multiply = { Coin c -> delegate * c.value } assert 2 * quarter + 1 * nickel + 2 * penny == 57 QCON 2010 - 56
  • 57. ...Coin example class CoinValues { static get(Integer self, String name) { self * Coin."${singular(name)}".value } static singular(String val) { val.endsWith('ies') ? val[0..-4] + 'y' : val.endsWith('s') ? val[0..-2] : val } } use (CoinValues) { © ASERT 2006-2010 assert 2.quarters + 1.nickel + 2.pennies == 57 } // EMC equivalent Integer.metaClass.getProperty = { String name -> def mp = Integer.metaClass.getMetaProperty(name) if (mp) return mp.getProperty(delegate) def singular = name.endsWith('ies') ? name[0..-4] + 'y' : name.endsWith('s') ? name[0..-2] : name delegate * Coin."$singular".value } assert 2.quarters + 1.nickel + 2.pennies == 57 QCON 2010 - 57
  • 58. Game example... // Trying out the game DSL idea by Sten Anderson from: // http://blogs.citytechinc.com/sanderson/?p=92 class GameUtils { static VOWELS = ['a', 'e', 'i', 'o', 'u'] static listItems(things) { def result = '' things.eachWithIndex{ thing, index -> if (index > 0) { © ASERT 2006-2010 if (index == things.size() - 1) result += ' and ' else if (index < things.size() - 1) result += ', ' } result += "${thing.toLowerCase()[0] in VOWELS ? 'an' : 'a'} $thin } result ?: 'nothing' } } import static GameUtils.* ... QCON 2010 - 58
  • 59. ...Game example... ... class Room { def description def contents = [] } ... © ASERT 2006-2010 QCON 2010 - 59
  • 60. ...Game example... ... class Player { def currentRoom def inventory = [] void look() { println "You are in ${currentRoom?.description?:'the void'} which contains ${listItems(currentRoom?.contents)} } void inv() { © ASERT 2006-2010 println "You are holding ${listItems(inventory)}" } void take(item) { if (currentRoom?.contents?.remove(item)) { inventory << item println "You took the $item" } else { println "I see no $item here" } } QCON 2010 - 60
  • 61. ...Game example... ... void drop(item) { if (inventory?.remove(item)) { currentRoom?.contents << item println "You dropped the $item" } else { println "You don't have the $item" } © ASERT 2006-2010 } def propertyMissing(String name) { if (metaClass.respondsTo(this, name)) { this."$name"() } name } } ... QCON 2010 - 61
  • 62. ... ...Game example... Room plainRoom = new Room(description:'a plain white room', contents:['dagger', 'emerald', 'key']) Player player = new Player(currentRoom:plainRoom) player.with{ inv look take dagger inv © ASERT 2006-2010 look take emerald inv look take key drop emerald inv look } assert player.inventory == ['dagger', 'key'] QCON 2010 - 62
  • 63. ...Game example ... // now try some error conditions plainRoom.description = null player.with { drop gold take gold drop emerald © ASERT 2006-2010 take emerald take emerald look } QCON 2010 - 63
  • 64. Grails Criteria // Account is a POJO in our domain/model def c = Account.createCriteria() def results = c { like("holderFirstName", "Fred%") and { between("balance", 500, 1000) eq("branch", "London") © ASERT 2006-2010 } maxResults(10) order("holderLastName", "desc") } // source: Grails doco: 5. Object Relational Mapping (GORM): 5.4.2 Criteria QCON 2010 - 64
  • 65. Grails Criteria Example // Book is a POJO in our domain/model def book = Book.findByTitle("The Stand") book = Book.findByTitleLike("Harry Pot%") book = Book.findByReleaseDateBetween( firstDate, secondDate ) © ASERT 2006-2010 book = Book.findByReleaseDateGreaterThan( someDate ) book = Book.findByTitleLikeOrReleaseDateLessThan( "%Something%", someDate ) books = Book.findAllByTitleLikeAndReleaseDateGreaterThan( "%Java%", new Date()-30) // source: Grails doco: 5. Object Relational Mapping (GORM): 5.4.1 Dynamic Finders QCON 2010 - 65
  • 66. Grails Bean Builder Example bb.beans { marge(Person) { name = "marge" husband = { Person p -> name = "homer" age = 45 props = [overweight:true, height:"1.8m"] } children = [bart, lisa] © ASERT 2006-2010 } bart(Person) { name = "Bart" age = 11 } lisa(Person) { name = "Lisa" age = 9 } } // source: 14. Grails and Spring: 14.3 Runtime Spring with the Beans DSL QCON 2010 - 66
  • 67. Groovy Lab Example // require GroovyLab import static org.math.array.Matrix.* import static org.math.plot.Plot.* def A = rand(10,3) // random Matrix of 10 rows and 3 columns def B = fill(10,3,1.0) // one Matrix of 10 rows and 3 columns def C = A + B // support for matrix addition with "+" or "-" def D = A - 2.0 // support for number addition with "+" or "-" def E = A * B // support for matrix multiplication or division © ASERT 2006-2010 def F = rand(3,3) def G = F**(-1) // support for matrix power (with integers only) println A // display Matrix content plot("A",A,"SCATTER") // plot Matrix values as ScatterPlot def M = rand(5,5) + id(5) //Eigenvalues decomposition println "M=n" + M println "V=n" + V(M) println "D=n" + D(M) println "M~n" + (V(M) * D(M) * V(M)**(-1)) QCON 2010 - 67
  • 68. Operator Overloading Example BigDecimal a = new BigDecimal(3.5d); BigDecimal b = new BigDecimal(4.0d); assert a.multiply(b).compareTo(new BigDecimal(14.0d)) == 0; assert a.multiply(b).equals(new BigDecimal(14.0d).setScale(1)); def c = 3.5, d = 4.0 assert c * d == 14.0 © ASERT 2006-2010 QCON 2010 - 68
  • 69. Type Transformation Example class InventoryItem { def weight, name InventoryItem(Map m) { this.weight = m.weight; this.name = m.name } InventoryItem(weight, name) { this.weight = weight; this.name = name } InventoryItem(String s) { © ASERT 2006-2010 s.find(/weight=(d*)/) { all, w -> this.weight = w } s.find(/name=(.*)/) { all, n -> this.name = n } } } def room = [:] def gold = [weight:50, name:'Gold'] as InventoryItem def emerald = [10, 'Emerald'] as InventoryItem def dagger = ['weight=5, name=Dagger'] as InventoryItem room.contents = [gold, emerald, dagger] room.contents.each{ println it.dump() } QCON 2010 - 69
  • 70. AST Builder • Numerous approaches, still evolving. “From code” approach: def result = new AstBuilder().buildFromCode { println "Hello World" } • Produces: BlockStatement -> ReturnStatement -> MethodCallExpression -> VariableExpression("this") -> ConstantExpression("println") -> ArgumentListExpression -> ConstantExpression("Hello World")
  • 71. Topics • Groovy Intro • Leveraging the language • Use and abuse of Design Patterns • Web Services • Writing DSLs © ASERT 2006-2010 Groovy Testing • Polyglot Groovy • Parallel Processing • Enterprise Groovy • More Info QCON 2010 - 71
  • 72. Types of Testing Unit Testing Mock/interaction testing Techniques State-based testing Testing DSLs ATDD/BDD Data-driven Logic-driven © ASERT 2006-2010 Integration Testing Model-driven Performance testing Acceptance Testing All-pairs & Web drivers combinations Non-web drivers Gpars Test runners QCON 2010 - 72
  • 73. Groovy's Value Add for Testing • Unit testing – Built-in asserts, support for JUnit 3&4 and TestNG, GroovyTestCase with shouldFail and other methods – Built-in mocking and compatible with Java mocking • Integration testing – Metaprogramming allows various kinds of IOC like © ASERT 2006-2010 intercepting and hooking up of components – Wealth of GDK methods for Ant, Processes, Files, Threads, etc. make the automating part much simpler • Acceptance Testing and Generally – Allows creation of English-like testing DSLs using Closures, builders, metaprogramming – Simpler syntax great for non hard-core testers – Grapes make tests easier to share QCON 2010 - 73
  • 74. Groovy and Testing Tool Spectrum* Utilities Runners AllPairs, Combinations Native Groovy, JUnit, TestNG, Spock, EasyB, Polyglot languages JBehave, Cucumber, Robot Framework Logic programming Threads, Parallel / Web Database SOAP / Other Concurrency libraries Drivers Drivers REST Drivers Data-driven libraries Drivers Networking libraries WebTest DbUnit FEST © ASERT 2006-2010 XML Processing GroovyWS WebDriver DataSets Email Read/write files / JWebUnit SqlUnit XML-RPC FTP Excel / Word / CSV Reporting, Logging Tellurium groovy.sql CXF AntUnit Selenium JPA Axis2 Telnet HtmlUnit JDO JAX-WS SSH Tools Watij BigTable JAX-RS Exec iTest2, SoapUI, Twist, HttpBuilder JDBC IDEs, JMeter, Text Cyberneko editors, Recorders, Sahi, Build Tools, CI * Tools/libraries/frameworks don't always neatly fall into one category – still useful conceptually QCON 2010 - 74
  • 75. HtmlUnit • 100% Java-based headless browser emulator – Can test any Web site: Java, .Net, PHP, Rails, ... • Open Source – Apache 2 license – Hosted at SourceForge – 7 committers (3 very active) – © ASERT 2006-2010 Very mature • Useful for: – Integration and acceptance testing – Screen scraping, deployment automation, ... • Used by other drivers: – Canoo WebTest , JWebUnit , WebDriver , JSFUnit , Celerity • Special features: – Easy ajax mode, emulation of multiple browsers QCON 2010 - 75
  • 76. HtmlUnit: Testing New Blog Post... @Grab('net.sourceforge.htmlunit:htmlunit:2.6') import com.gargoylesoftware.htmlunit.WebClient def client = new WebClient() def page = client.getPage('http://localhost:8080/postForm') // check page title assert 'Welcome to SimpBlog' == page.titleText © ASERT 2006-2010 // fill in blog entry and post it def form = page.getFormByName('post') form.getInputByName('title'). setValueAttribute('Bart was here (and so was HtmlUnit)') form.getSelectByName('category').getOptions().find{ it.text == 'Home' }.setSelected(true) form.getTextAreaByName('content').setText('Cowabunga Dude!') def result = form.getInputByName('btnPost').click() ... QCON 2010 - 76
  • 77. ...HtmlUnit: Testing New Blog Post ... // check blog post details assert result.getElementsByTagName('h1').item(0). textContent.matches('Post.*: Bart was here.*') def h3headings = result.getElementsByTagName('h3') © ASERT 2006-2010 assert h3headings.item(1).textContent == 'Category: Home' assert h3headings.item(2).textContent == 'Author: Bart' // expecting: // <table><tr><td><p>Cowabunga Dude!</p></td></tr></table> def cell = result.getByXPath('//TABLE//TR/TD')[0] def para = cell.getFirstChild() assert para.textContent == 'Cowabunga Dude!' QCON 2010 - 77
  • 78. WebTest testing Web Sites def ant = new AntBuilder() def webtest_home = System.properties.'webtest.home' ant.taskdef(resource:'webtest.taskdef') { classpath { pathelement(location:"$webtest_home/lib") fileset(dir:"$webtest_home/lib", includes:"**/*.jar") } } © ASERT 2006-2010 def config_map = [:] ['protocol','host','port','basepath','resultfile', 'resultpath', 'summary', 'saveresponse','defaultpropertytype'].each { config_map[it] = System.properties['webtest.'+it] } ant.testSpec(name:'groovy: Test Groovy Scripting at creation time') { config(config_map) steps { invoke(url:'linkpage.html') for (i in 1..10) { verifyText(description:"verify number ${i} is on pages", text:"${i}") } } } QCON 2010 - 78
  • 79. WebTest testing Emails def ant = new AntBuilder() def webtest_home = System.properties.'webtest.home' ant.taskdef(resource:'webtest.taskdef'){ classpath(){ pathelement(location:"$webtest_home/lib") fileset(dir:"$webtest_home/lib", includes:"**/*.jar") } } © ASERT 2006-2010 ant.testSpec(name:'Email Test'){ steps { emailSetConfig(server:'localhost', password:'password', username:'devteam@mycompany.org', type:'pop3') emailStoreMessageId(subject:'/Build notification/', property:'msg') emailStoreHeader(property:'subject', messageId:'#{msg}', headerName:'Subject') groovy('''def subject = step.webtestProperties.subject assert subject.startsWith('Build notification')''') emailMessageContentFilter(messageId:'#{msg}') verifyText(text:'Failed build') } } QCON 2010 - 79
  • 80. Spock Testing Framework... © ASERT 2006-2010 QCON 2010 - 80
  • 81. ...Spock Testing Framework • Testing framework for Java and Groovy • Highly expressive specification language – No assertion API – No record & replay @Speck mocking API @RunWith(Sputnik) – No class PublisherSubscriberSpeck { superfluous def "events are received by all subscribers"() { © ASERT 2006-2010 annotations def pub = new Publisher() – Meaningful def sub1 = Mock(Subscriber) assert error def sub2 = Mock(Subscriber) messages pub.subscribers << sub1 << sub2 when: pub.send("event") then: – Extensible 1 * sub1.receive("event") – Compatible 1 * sub2.receive("event") with JUnit } reportingwise } QCON 2010 - 81
  • 82. Spock Example... import com.gargoylesoftware.htmlunit.WebClient import spock.lang.* import org.junit.runner.RunWith @Speck () @RunWith (Sputnik) class TestSimpBlogSpock { def page, subheadings, para, form, result @Unroll("When #author posts a #category blog with content '#content' it shoul © ASERT 2006-2010 def "when creating a new blog entry"() { given: page = new WebClient().getPage('http://localhost:8080/postForm') form = page.getFormByName('post') when: form.getInputByName('title').setValueAttribute("$author was here (and so form.getSelectByName('category').getOptions().find { it.text == category form.getSelectByName('author').getOptions().find { it.text == author }.se form.getTextAreaByName('content').setText(content) result = form.getInputByName('btnPost').click() subheadings = result.getElementsByTagName('h3') para = result.getByXPath('//TABLE//TR/TD/P')[0] ... QCON 2010 - 82
  • 83. ...Spock Example ... then: page.titleText == 'Welcome to SimpBlog' result.getElementsByTagName('h1').item(0).textContent.matches("Post.*: $auth subheadings.item(1).textContent == "Category: $category" subheadings.item(2).textContent == "Author: $author" and: // Optional use of 'and:' para.textContent == content © ASERT 2006-2010 where: author << ['Bart', 'Homer', 'Lisa'] category << ['Home', 'Work', 'Food'] content << ['foo', 'bar', 'baz'] } } QCON 2010 - 83
  • 84. EasyB • Description: BDD, Rspec-like testing library narrative 'segment flown', { as_a 'frequent flyer' i_want 'to accrue rewards points for every segment I fly' so_that 'I can receive free flights for my dedication to the airline' } scenario 'segment flown', { given 'a frequent flyer with a rewards balance of 1500 points' © ASERT 2006-2010 when 'that flyer completes a segment worth 500 points' then 'that flyer has a new rewards balance of 2000 points' } scenario 'segment flown', { given 'a frequent flyer with a rewards balance of 1500 points', { flyer = new FrequentFlyer(1500) } when 'that flyer completes a segment worth 500 points', { flyer.fly(new Segment(500)) } then 'that flyer has a new rewards balance of 2000 points', { flyer.pointsBalance.shouldBe 2000 } } QCON 2010 - 84
  • 85. EasyB Example ... • When run will be marked as pending – perfect for ATDD scenario "Bart posts a new blog entry", { given "we are on the create blog entry page" when "I have entered 'Bart was here' as the title" and "I have entered 'Cowabunga Dude!' into the content" and "I have selected 'Home' as the category" © ASERT 2006-2010 and "I have selected 'Bart' as the author" and "I click the 'Create Post' button" then "I expect the entry to be posted" } QCON 2010 - 85
  • 86. ...EasyB Example... description "Post Blog Entry Feature" narrative "for feature", { as_a "Blogger" i_want "to be able to post a blog" so_that "I can keep others informed" } before "posting blog", { given "we are on the create blog entry page", { © ASERT 2006-2010 webClient = new com.gargoylesoftware.htmlunit.WebClient() page = webClient.getPage('http://localhost:8080/postForm') } } scenario "Bart was here blog", { when "I have entered 'Bart was here' as the title", { form = page.getFormByName('post') form.getInputByName('title').setValueAttribute( 'Bart was here (and so was EasyB)') } ... QCON 2010 - 86
  • 87. ...EasyB Example... ... and "I have entered 'Cowabunga Dude!' into the content", { form.getTextAreaByName('content').setText('Cowabunga Dude!') } and "I have selected 'Home' as the category", { form.getSelectByName('category').getOptions().find { it.text == 'Home' }.setSelected( } and "I click the 'Create Post' button", { result = form.getInputByName('btnPost').click() } © ASERT 2006-2010 then "I expect the entry to be posted", { // check blog post details assert result.getElementsByTagName('h1').item(0).textContent.matches('Post.*: Bart wa def h3headings = result.getElementsByTagName('h3') assert h3headings.item(1).textContent == 'Category: Home' // traditional style h3headings.item(2).textContent.shouldBe 'Author: Bart' // BDD style // expecting: <table><tr><td><p>Cowabunga Dude!</p></td></tr></table> def cell = result.getByXPath('//TABLE//TR/TD')[0] def para = cell.firstChild assert para.textContent == 'Cowabunga Dude!' // para.shouldHave textContent: 'Cowabunga Dude!' } } QCON 2010 - 87
  • 88. ...EasyB Example... © ASERT 2006-2010 QCON 2010 - 88
  • 89. ...EasyB Example 2 scenarios (including 1 pending) executed successfully. Story: simp blog initial scenario Bart posts a new blog entry [PENDING] given we are on the create blog entry page when I have entered 'Bart was here' as the title when I have entered 'Cowabunga Dude!' into the content [PENDING] when I have selected 'Home' as the category [PENDING] when I have selected 'Bart' as the author [PENDING] when I click the 'Create Post' button [PENDING] then I expect the entry to be posted [PENDING] Story: simp blog easyb is preparing to process 2 file(s) © ASERT 2006-2010 Post Blog Entry Feature Running simp blog initial story (SimpBlogInitialStory.groovy) for feature Scenarios run: 1, Failures: 0, Pending: 1, Time elapsed: 1.049 sec As a Blogger Running simp blog story (SimpBlogStory.groovy) I want to be able to post a blog Scenarios run: 1, Failures: 0, Pending: 0, Time elapsed: 1.356 sec So that I can keep others informed given we are on the create blog entry page 2 total behaviors ran (including 1 pending behavior) with no failures easyb execution passed scenario Bart was here blog when I have entered 'Bart was here' as the title when I have entered 'Cowabunga Dude!' into the content when I have selected 'Home' as the category when I click the 'Create Post' button then I expect the entry to be posted QCON 2010 - 89
  • 90. Cucumber # language: en • Description Feature: Addition In order to avoid silly mistakes – Loose coupling As a math idiot between text spec I want to be told the sum of two numbers and step defns Scenario Outline: Add two numbers Given I have entered <input_1> into the calculator And I have entered <input_2> into the calculator When I press <button> Then the stored result should be <output> Examples: © ASERT 2006-2010 | input_1 | input_2 | button | output | | 20 | 30 | add | 50 | | 2 | 5 | add | 7 | | 0 | 40 | add | 40 | # language: en Feature: Division In order to avoid silly mistakes Cashiers must be able to calculate a fraction Scenario: Regular numbers Given I have entered 3 into the calculator And I have entered 2 into the calculator When I press divide Then the stored result should be 1.5 QCON 2010 - 90
  • 91. Cucumber Example... # language: en @newpost Feature: New Blog Post In order to create a new blog entry Bloggers should be able to select their name and category and enter text © ASERT 2006-2010 Scenario: New Posting Given we are on the create blog entry page When I have entered "Bart was here" as the title And I have entered "Cowabunga Dude!" as the content And I have selected "Home" from the "category" dropdown And I have selected "Bart" from the "author" dropdown And I click the 'Create Post' button Then I should see a heading message matching "Post.*: Bart was here.*" QCON 2010 - 91
  • 92. ...Cucumber Example... © ASERT 2006-2010 QCON 2010 - 92
  • 93. ...Cucumber Example import com.gargoylesoftware.htmlunit.WebClient this.metaClass.mixin(cuke4duke.GroovyDsl) Given ~/we are on the create blog entry page/, { -> page = new WebClient().getPage('http://localhost:8080/postForm') } When(~/I have entered "(.*)" as the title/) {String title -> form = page.getFormByName('post') form.getInputByName('title').setValueAttribute(title + ' (and so was Cucumber)') } When(~'I have entered "(.*)" as the content') {String content -> © ASERT 2006-2010 form.getTextAreaByName('content').setText(content) } When(~'I have selected "(.*)" from the "(.*)" dropdown') {String option, String name -> form.getSelectByName(name).getOptions().find { it.text == option }.setSelected(true) } When(~"I click the 'Create Post' button") { -> result = form.getInputByName('btnPost').click() } Then(~'I should see a heading message matching "(.*)"') {String pattern -> // ensureThat result.getElementsByTagName('h1').item(0).textContent.matches(pattern) assert result.getElementsByTagName('h1').item(0).textContent.matches(pattern) } QCON 2010 - 93
  • 94. Cucumber Data Driven Example... # language: en @newpost Feature: New Blog Post In order to create a new blog entry Bloggers should be able to select their name and category and enter text Scenario Outline: New Posting Given we are on the create blog entry page © ASERT 2006-2010 When I have entered "<title>" as the title And I have entered "<content>" as the content And I have selected "<category>" from the "category" dropdown And I have selected "<author>" from the "author" dropdown And I click the 'Create Post' button Then I should see a heading message matching "Post.*: <title>.*" Examples: | title | content | category | author | | Title 1 | Content 1 | Home | Bart | | Title 2 | Content 2 | Work | Homer | | Title 3 | Content 3 | Food | Marge | QCON 2010 - 94
  • 95. ...Cucumber Data Driven Example © ASERT 2006-2010 QCON 2010 - 95
  • 96. JBehave • Description – Behaviour-driven development in Java • Also works out of the box for Groovy – Behavior scenarios written in text • Use the words Given, When, Then and And. – Mapped using regular expressions and annotations © ASERT 2006-2010 to step methods – Web Runner available for non-technical users to easily run tests – Hooks to Selenium available in JBehave Web • Other Java libraries (e.g. HtmlUnit) easy to use too – Supports parameter converters • Getting 'String' parameters into appropriate Object values – Supports a 'StepDoc' function • For listing available scenario clauses QCON 2010 - 96