SlideShare a Scribd company logo
1 of 72
Spock: A Highly Logical
Way To Test
Howard M. Lewis Ship
TWD Consulting
hlship@gmail.com
@hlship
                       © 2012 Howard M. Lewis Ship
Why Don't We Test?

                       Hard To Get Started

               My Code's Perfect     Code Too Monolithic

    Tests Broke, Nobody Fixed, Turned Off



              Uh, We Used To?        More Code Is More Code




                      Test Code Hard To Maintain
What if ...

 Test code was readable?
 Tests were concise?
 Test reports were useful?
 Failures were well described?
 Mocking was easy?




… wouldn't that be most logical?
My Path
               Wrote own test framework –
     1990's
               in PL/1 – 5000 - 7000 tests

                First JUnit tests (Tapestry
     2001
                     template parser)
    2003-ish      Started using TestNG
    2004-ish    Started using EasyMock
    2005-ish    Started using Selenium 1

    2006-ish       Dabbled in Groovy

     2010             Spock! ~ 0.4
Terminology
                              Fixture
Specification


                                        Collaborator
                 System
   Feature
    Feature      Under
               Specification
                                        Collaborator
First Specification                                              sp
                                                                  o
SkySpecification.groovy                                       gro ck 0
                                                                 ov     .
package org.example                                                 y-1 6-
                                                                       .8
import spock.lang.*

class SkySpecification extends Specification {

    ...
}                                 All Specifications extend from this base class



                      Sky.java
                      package org.example.sus;

                      public class Sky {
                        public String getColor() {
                          return "blue";
                        }
                      }
Feature Methods

      def "sky is blue"() {
        setup:
        def sky = new Sky()

          expect:
          sky.color == "blue"
      }
Execution
$ gradle test
Note: the Gradle build daemon is an experimental feature.
As such, you may experience unexpected build failures. You may need to
occasionally stop the daemon.
:compileJava UP-TO-DATE
:compileGroovy UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:compileTestJava UP-TO-DATE
:compileTestGroovy                   $ tree build/reports/
:processTestResources UP-TO-DATE     build/reports/
:testClasses                         └── tests
:test                                    ├── base-style.css
                                         ├── css3-pie-1.0beta3.htc
BUILD SUCCESSFUL                         ├── index.html
                                         ├── org.example.SkySpecification.html
Total time: 3.831 secs                   ├── org.example.html
~/workspaces/github/spock-examples       ├── report.js
$                                        └── style.css

                                     1 directory, 7 files
                                     ~/workspaces/github/spock-examples
                                     $
sky.color == "green"
Feature Method Blocks
                      def "sky is blue"() {
                        setup:
                        def sky = new Sky()

                          expect:
                          sky.color == "blue"
                      }

 setup: or given:
 expect:
 when:
 then:
 where:
 cleanup:
 Feature methods must contain at least one block
 otherwise, not a feature method
setup:

 Initialization of the fixture
 Always at top of method
 Can't be repeated
 Can be given: instead
 Anything up to first label is implicit setup:
expect:                      Response

                  expect:
                  sky.color == "blue"




                  Stimulus



 Combines stimulus and response
 Contains only conditions and variable definitions
   Conditions assert Groovy truth
 Best for purely functional (no-side effects) functions
when: / then:
                     def "clouds are grey"() {
                       def sky = new Sky()

                         when:
          Stimulus       sky.addStormSystem()

                         then:
                         sky.color == "grey"    Response
                     }




 Used as a pair
 Tests method with side effects
 then: may only contain conditions, exception
 conditions, interactions and variable definitions
when: / then:
          def "clouds are grey"() {
            def sky = new Sky()

              when:
              sky.addStormSystem()

              then:
              sky.color == "grey"
          }
Test driven
Sky.java
package org.example.sus;

public class Sky {

    private String color = "blue";

    public String getColor() {
      return color;
    }

    public void addStormSystem() {
      color = "grey";
    }
}
then: Old Values

 def "pushing an element on the stack increases its size by one"() {
   def stack = new Stack()
   when:
   stack.push("element")
   then:
   stack.size() == old(stack.size()) + 1
 }

                          Expression value captured before where: block
Extended Assert
  def "use of extended assert"() {

      expect:
      assert 4 == 5, "Big Brother says there are four fingers"
  }
cleanup:
              setup:
              def file = new File("/some/path")
              file.createNewFile()

              // ...

              cleanup:
              file.delete()




 Cleanup external resources
 Always invoked, even if previous exceptions
where:
             def "length of crew member names"() {
               expect:
               name.length() == length

                 where:
                 name     |   length
                 "Spock"  |   5
                 "Kirk"   |   4
                 "Scotty" |   6
             }




 Parameterizes feature method with data
 Must be last block
 Can use | or || as separator
where:



         One entry for three
          feature method
            executions
where: using lists
       def "length of crew member names (using lists)"() {
         expect:
         name.length() == length

           where:
           name << ["Spock", "Kirk", "Scotty"]
           length << [5, 4, 6]
       }

                  Could come from external file or database




   where:
   [name, age, gender] = sql.execute("select name, age, sex from ⏎
    customer")
where: derived values
   def "length of crew member names (with derived values)"() {
     expect:
     name.length() == length

       where:
       name << ["Spock", "Kirk", "Scotty"]
       length = name.length()
   }
Block labels
               def "clouds are grey"() {

                   given: "A fresh Sky"
                   def sky = new Sky()

                   when: "A storm system rolls in"
                   sky.addStormSystem()

                   then: "It all goes grey"
                   sky.color == "grey"
               }




 Allowed, but not (currently) used
 and: "block" allowed, does nothing
Beyond Feature Methods
Fields
         package org.example

         import org.example.sus.Sky
         import spock.lang.Specification

         class SkySpecification extends Specification {

             def sky = new Sky()            New for each feature method
             def "sky is blue by default"() {
               expect:
               sky.color == "blue"
             }

             def "clouds are grey"() {

                 given: "A fresh Sky"

                 when: "A storm system rolls in"
                 sky.addStormSystem()

                 then: "It all goes grey"
                 sky.color == "grey"
             }
         }
Shared Fields

            Created once, shared across all instances


   class MySpecification extends Specification {
     @Shared def resource = new AnExepensiveResource()

       static final PASSWORD = "sayfriendandenter"
       …
   }

                    Statics should be final and immutable
Fixture Methods
               def setup() { … }

               def cleanup() { … }

 Create / initialize instance of Specification
 Invoke setup()
 Invoke feature method
 Invoke cleanup()
Fixture Methods
           def setupSpec() { … }

           def cleanupSpec() { … }



 Instance created for Specification setup / cleanup
 May only access @Shared and static fields
Exception Conditions
def ins = new ClassInstantiatorImpl(ContextCatcher, ⏎
  ContextCatcher.constructors[0], null)

def "may not add a duplicate instance context value"() {

    given:
    def ins2 = ins.with(String, "initial value")

    when:
    ins2.with(String, "conflicting value")

    then:
    def e = thrown()      Or: e   = thrown(IllegalStateException)

    e.message == "An instance context value of type java.lang.String ⏎
    has already been added."
}
Typed Exceptions
def ins = new ClassInstantiatorImpl(ContextCatcher, ⏎
  ContextCatcher.constructors[0], null)

def "may not add a duplicate instance context value"() {

    given:
    def ins2 = ins.with(String, "initial value")

    when:
    ins2.with(String, "conflicting value")

    then:
    IllegalStateException e = thrown()

    e.message == "An instance context value of type java.lang.String ⏎
    has already been added."
}
notThrown()
             def "HashMap accepts null key"() {
               setup:
               def map = new HashMap()
              
               when:
               map.put(null, "elem")
              
               then:
               notThrown(NullPointerException)
             }
                     Documentation value only




Also: noExceptionThrown()
Mocks and Interactions
Fixture
Specification


                                        Collaborator
   Feature     SystemUnder
    Feature
               Specification

                                        Collaborator
Configured
  System        Instance
  Under
Specification
               Mock Object
Payment
                                       CustomerDAO
               Processor


PaymentProcessor.groovy
package org.example.sus

class PaymentProcessor {

    CustomerDAO customerDAO

    def applyPayment(long customerId, BigDecimal amount) {

        Customer customer = customerDAO.getById(customerId)

        if (customer == null)
          throw new IllegalArgumentException("No customer #$customerId")

        customer.accountBalance += amount        CustomerDAO.java
                                                 package org.example.sus;
        customerDAO.update(customer)
    }                                            public interface CustomerDAO {
}
                                                     Customer getById(long id);

                                                     void update(Customer customer);
                                                 }
class ApplyPaymentSpecification extends Specification {

     CustomerDAO dao = Mock()      Factory method
     PaymentProcessor processor

     def setup() {
       processor = new PaymentProcessor(customerDAO: dao)
     }

     …
}|
Defining Mock Behavior

     def "unknown customer id is an exception"() {
       when:
       processor.applyPayment(12345, 100)

         then:
         1 * dao.getById(12345) >> null            Define behavior for
                                                 preceding when: block
         IllegalArgumentException e = thrown()

         e.message == "No customer #12345"
     }
def "valid customer id for update"() {
  when:
  processor.applyPayment(customer.id, 200)

    then:
    1 * dao.getById(customer.id) >> customer
    1 * dao.update(customer)

    customer.accountBalance == 500

    where:
    customer = new Customer(id: 98765, accountBalance: 300)
}
Target and Method Constraints
                                Argument Constraints



  1 * dao.getById(12345) >> null
  Number of invocations:
                                                 Returns a value
      cardinality
Cardinality
 Omitted
 ➠ Interaction is optional, must have return value
 n * mock.method(…)
 ➠ exactly n times
 (n.._) * mock.method(…)
 ➠ at least n times
 (_..n) * mock.method(…)
 ➠ Up to n times
Argument Constraints
 _
 ➠ Any argument

 *_
 ➠ Any number of arguments

 !null
 ➠ Any non-null argument
 value
 ➠ Argument equals value
 !value
 ➠ Argument not equal to value

 _ as Type
 ➠ Non-null argument assignable to Type
Closures for Argument Contraints
class InteractionsSpecification extends Specification {

  Operation mock = Mock()

  interface Operation {
    Object op(input)
  }

  def isOdd(input) { input % 2 != 0 }                 Helper method
  def "closure for parameter constraint"() {
    when:
    assert mock.op(3) == 6
    assert mock.op(7) == 14

      then:
      (2..7) * mock.op({ isOdd(it) }) >> { 2 * it }
  }

                  Return value computed by closure
def "wrong number of invocations"() {
         when:
         assert mock.op(7) == 14

           then:
           (2..7) * mock.op({ isOdd(it) }) >> { 2 * it }
       }




Too few invocations for:

(2..7) * mock.op({ result = 2 * it; return it % 2 != 0 }) >> { result }   (1 invocation)

&   at org.spockframework.mock.InteractionScope.verifyInteractions(InteractionScope.java:66)
&   at org.spockframework.mock.MockController.leaveScope(MockController.java:35)
&   at org.example.InteractionsSpecification.wrong number of
invocations(InteractionsSpecification.groovy:32)
Mocks are Lenient


    def "parameter does   not match closure constraint"() {
      when:
      assert mock.op(3)   == 6
      assert mock.op(4)   == null
      assert mock.op(7)   == 14

        then:
        _ * mock.op({ isOdd(it) }) >> { 2 * it }
    }
Less Lenient Mocks
         def "detecting parameter that doesn't match"() {
           when:
           assert mock.op(3) == 6
           assert mock.op(4) == null
           assert mock.op(7) == 14

             then:
             _ * mock.op({ isOdd(it) }) >> { 2 * it }

             0 * _          aka "any interaction"
         }



Too many invocations for:

0 * _   (1 invocation)

Last invocation: mock.op(4)

&   at org.spockframework.mock.MockInteraction.accept(MockInteraction.java:58)
&   at org.spockframework.mock.MockInteractionDecorator.accept(MockInteractionDecorator.java:41)
&   at org.spockframework.mock.InteractionScope$1.accept(InteractionScope.java:38)
&   at org.spockframework.mock.MockController.dispatch(MockController.java:42)
&   at org.spockframework.mock.DefaultMockFactory$1.invoke(DefaultMockFactory.java:70)
&   at org.example.InteractionsSpecification.detecting parameter that doesn't
match(InteractionsSpecification.groovy:58)
Target and Method Constraints


     Target Constraint



  1 * dao.getById(12345) >> null

                     Method Constraint
Target Constraints


 name
 ➠ Match the mock in the variable or field
 _
 ➠ Match any mock
Method Constraints

 name
 ➠ Match method with given name
 /re/
 ➠ Match methods matching regular expression
 ➠ e.g. bean./set.*/(_)
 _
 ➠ Match any method
Return Values

 >> value
 ➠ Return the value
 >> { … }
 ➠ Evaluate the closure and return the result
 >>> [ a, b, c]
 ➠ Return a, then return b, then keep returning c
 ➠ Any kind of iterable list, any size
Chained Return Values


   then:
     service.getStatus()
       >>> ["ok", "ok", "fail"]
       >> { throw new RuntimeException("Status failure."); }


                              The last value sticks
Ordered Interactions

          def "test three amigos"() {
            when:
            facade.doSomething()

              then:
              1 * collab1.firstPart()       No order checking
              1 * collab2.secondPart()        on firstPart(),
                                              secondPart()
              then:
              1 * collab3.thirdPart()
          }

                              thirdPart() only
                            allowed after both
                                 firstPart(),
                               secondPart()
Stubbing


           def "frobs the gnop"() {
                                            A "global interaction"
               checker.isValid(_) >> true      valid to end of
               when:                               method
               …
           }
Extensions
@Unroll
     @Unroll
     def "Crew member '#name' length is #length"() {
       expect:
       name.length() == length

         where:
         name       |   length
         "Spock"    |   5
         "Kirk"     |   4
         "Scotty"   |   6
     }
@Unroll
class CanonicalWhereBlockExampleSpecification extends Specification {

    def "Crew member '#name' length is #length"() {
      …
    }

    def "length of crew member names (using lists)"() {
      …
    }

    def "length of crew member names (with derived values)"() {
      …
    }
}
@Timeout
      @Timeout(5)
      def "can access data in under five seconds"() {
        …
      }

      @Timeout(value=100, unit=TimeUnit.MILLISECONDS)
      def "can update data in under 100 ms"() {
        …
      }




Feature and fixture methods run on main thread
A second thread may interrupt the main thread
Can be placed on class to affect all feature methods
@Stepwise
    @Stepwise
    class BuildingBlocksSpecification extends Specification {

      def "first step()" { … }

      def "second step"() { … }

      def "third step"() { … }




Feature methods run in declaration order
Failed methods cause remainder to be skipped
@AutoCleanup
               def DatabaseSpecification … {

                   @AutoCleanup @Shared
                   Connection connection

                   …
               }



Will invoke close() on field's value
Exceptions are reported but are not failures
quiet=true
➠ Don't report exceptions
value attribute is name of method to invoke
@Ignore / @IgnoreRest

 Used to temporarily control which feature methods
 execute
 @Ignore
 ➠ Ignore this method, run others
 @IgnoreRest
 ➠ Run this method, ignore others
More Info
https://github.com/spockframework/spock
http://code.google.com/p/spock/
http://docs.spockframework.org
https://github.com/hlship/spock-examples
http://howardlewisship.com
Q&A

More Related Content

What's hot

G*におけるソフトウェアテスト・シーズンIII
G*におけるソフトウェアテスト・シーズンIIIG*におけるソフトウェアテスト・シーズンIII
G*におけるソフトウェアテスト・シーズンIIITakuma Watabiki
 
Advanced Java Practical File
Advanced Java Practical FileAdvanced Java Practical File
Advanced Java Practical FileSoumya Behera
 
Unit/Integration Testing using Spock
Unit/Integration Testing using SpockUnit/Integration Testing using Spock
Unit/Integration Testing using SpockAnuj Aneja
 
Clojure - A new Lisp
Clojure - A new LispClojure - A new Lisp
Clojure - A new Lispelliando dias
 
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...julien.ponge
 
Advance Java Programs skeleton
Advance Java Programs skeletonAdvance Java Programs skeleton
Advance Java Programs skeletonIram Ramrajkar
 
Software Testing - Invited Lecture at UNSW Sydney
Software Testing - Invited Lecture at UNSW SydneySoftware Testing - Invited Lecture at UNSW Sydney
Software Testing - Invited Lecture at UNSW Sydneyjulien.ponge
 
What’s new in C# 6
What’s new in C# 6What’s new in C# 6
What’s new in C# 6Fiyaz Hasan
 
Apache Commons - Don\'t re-invent the wheel
Apache Commons - Don\'t re-invent the wheelApache Commons - Don\'t re-invent the wheel
Apache Commons - Don\'t re-invent the wheeltcurdt
 
Stubる - Mockingjayを使ったHTTPクライアントのテスト -
Stubる - Mockingjayを使ったHTTPクライアントのテスト -Stubる - Mockingjayを使ったHTTPクライアントのテスト -
Stubる - Mockingjayを使ったHTTPクライアントのテスト -Kenji Tanaka
 
Programming with Python and PostgreSQL
Programming with Python and PostgreSQLProgramming with Python and PostgreSQL
Programming with Python and PostgreSQLPeter Eisentraut
 
5. Ввод-вывод, доступ к файловой системе
5. Ввод-вывод, доступ к файловой системе5. Ввод-вывод, доступ к файловой системе
5. Ввод-вывод, доступ к файловой системеDEVTYPE
 
Riga Dev Day 2016 - Having fun with Javassist
Riga Dev Day 2016 - Having fun with JavassistRiga Dev Day 2016 - Having fun with Javassist
Riga Dev Day 2016 - Having fun with JavassistAnton Arhipov
 
Refactoring In Tdd The Missing Part
Refactoring In Tdd The Missing PartRefactoring In Tdd The Missing Part
Refactoring In Tdd The Missing PartGabriele Lana
 
Important java programs(collection+file)
Important java programs(collection+file)Important java programs(collection+file)
Important java programs(collection+file)Alok Kumar
 

What's hot (20)

G*におけるソフトウェアテスト・シーズンIII
G*におけるソフトウェアテスト・シーズンIIIG*におけるソフトウェアテスト・シーズンIII
G*におけるソフトウェアテスト・シーズンIII
 
Advanced Java Practical File
Advanced Java Practical FileAdvanced Java Practical File
Advanced Java Practical File
 
Unit/Integration Testing using Spock
Unit/Integration Testing using SpockUnit/Integration Testing using Spock
Unit/Integration Testing using Spock
 
Clojure - A new Lisp
Clojure - A new LispClojure - A new Lisp
Clojure - A new Lisp
 
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
 
Java 7 LavaJUG
Java 7 LavaJUGJava 7 LavaJUG
Java 7 LavaJUG
 
Unit Testing with Foq
Unit Testing with FoqUnit Testing with Foq
Unit Testing with Foq
 
Advance Java Programs skeleton
Advance Java Programs skeletonAdvance Java Programs skeleton
Advance Java Programs skeleton
 
Software Testing - Invited Lecture at UNSW Sydney
Software Testing - Invited Lecture at UNSW SydneySoftware Testing - Invited Lecture at UNSW Sydney
Software Testing - Invited Lecture at UNSW Sydney
 
Ad java prac sol set
Ad java prac sol setAd java prac sol set
Ad java prac sol set
 
What’s new in C# 6
What’s new in C# 6What’s new in C# 6
What’s new in C# 6
 
Apache Commons - Don\'t re-invent the wheel
Apache Commons - Don\'t re-invent the wheelApache Commons - Don\'t re-invent the wheel
Apache Commons - Don\'t re-invent the wheel
 
Stubる - Mockingjayを使ったHTTPクライアントのテスト -
Stubる - Mockingjayを使ったHTTPクライアントのテスト -Stubる - Mockingjayを使ったHTTPクライアントのテスト -
Stubる - Mockingjayを使ったHTTPクライアントのテスト -
 
Programming with Python and PostgreSQL
Programming with Python and PostgreSQLProgramming with Python and PostgreSQL
Programming with Python and PostgreSQL
 
5. Ввод-вывод, доступ к файловой системе
5. Ввод-вывод, доступ к файловой системе5. Ввод-вывод, доступ к файловой системе
5. Ввод-вывод, доступ к файловой системе
 
Riga Dev Day 2016 - Having fun with Javassist
Riga Dev Day 2016 - Having fun with JavassistRiga Dev Day 2016 - Having fun with Javassist
Riga Dev Day 2016 - Having fun with Javassist
 
Refactoring In Tdd The Missing Part
Refactoring In Tdd The Missing PartRefactoring In Tdd The Missing Part
Refactoring In Tdd The Missing Part
 
Spockを使おう!
Spockを使おう!Spockを使おう!
Spockを使おう!
 
Important java programs(collection+file)
Important java programs(collection+file)Important java programs(collection+file)
Important java programs(collection+file)
 
Server1
Server1Server1
Server1
 

Viewers also liked

Jenkinsプラグイン開発
Jenkinsプラグイン開発Jenkinsプラグイン開発
Jenkinsプラグイン開発Takahisa Wada
 
Androidリリース作業の効率化(2)
Androidリリース作業の効率化(2)Androidリリース作業の効率化(2)
Androidリリース作業の効率化(2)Kenichi Kambara
 
Groovy, Transforming Language
Groovy, Transforming LanguageGroovy, Transforming Language
Groovy, Transforming LanguageUehara Junji
 
Spock Framework
Spock FrameworkSpock Framework
Spock FrameworkIsmael
 
Testing Web Applications with GEB
Testing Web Applications with GEBTesting Web Applications with GEB
Testing Web Applications with GEBHoward Lewis Ship
 
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume LaforgeGroovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume LaforgeGuillaume Laforge
 
function list
function listfunction list
function listkyon mm
 
レガシーコード改善はじめました 横浜道場
レガシーコード改善はじめました 横浜道場レガシーコード改善はじめました 横浜道場
レガシーコード改善はじめました 横浜道場Hiroyuki Ohnaka
 
Gradle a new Generation Build Tool
Gradle a new Generation Build ToolGradle a new Generation Build Tool
Gradle a new Generation Build ToolShinya Mochida
 
Jenkinsを用いたAndroidアプリビルド作業効率化
Jenkinsを用いたAndroidアプリビルド作業効率化Jenkinsを用いたAndroidアプリビルド作業効率化
Jenkinsを用いたAndroidアプリビルド作業効率化Kenichi Kambara
 
GradleによるG*なビルドシステムの構築
GradleによるG*なビルドシステムの構築GradleによるG*なビルドシステムの構築
GradleによるG*なビルドシステムの構築Masatoshi Hayashi
 
Groovy Testing Aug2009
Groovy Testing Aug2009Groovy Testing Aug2009
Groovy Testing Aug2009guest4a266c
 
AgileJapan2010 基調講演:野中郁次郎先生による「実践知のリーダシップ~スクラムと知の場作り」
AgileJapan2010 基調講演:野中郁次郎先生による「実践知のリーダシップ~スクラムと知の場作り」AgileJapan2010 基調講演:野中郁次郎先生による「実践知のリーダシップ~スクラムと知の場作り」
AgileJapan2010 基調講演:野中郁次郎先生による「実践知のリーダシップ~スクラムと知の場作り」Kenji Hiranabe
 
Spock Framework 2
Spock Framework 2Spock Framework 2
Spock Framework 2Ismael
 
Groovier testing with Spock
Groovier testing with SpockGroovier testing with Spock
Groovier testing with SpockRobert Fletcher
 
Groovy 1.8の新機能について
Groovy 1.8の新機能についてGroovy 1.8の新機能について
Groovy 1.8の新機能についてUehara Junji
 
Gradle talk, Javarsovia 2010
Gradle talk, Javarsovia 2010Gradle talk, Javarsovia 2010
Gradle talk, Javarsovia 2010Tomek Kaczanowski
 
うさぎ組 in G* WorkShop -うさみみの日常-
うさぎ組 in G* WorkShop -うさみみの日常-うさぎ組 in G* WorkShop -うさみみの日常-
うさぎ組 in G* WorkShop -うさみみの日常-kyon mm
 
The outlineoftestprocess
The outlineoftestprocessThe outlineoftestprocess
The outlineoftestprocesskyon mm
 

Viewers also liked (20)

Jenkinsプラグイン開発
Jenkinsプラグイン開発Jenkinsプラグイン開発
Jenkinsプラグイン開発
 
Androidリリース作業の効率化(2)
Androidリリース作業の効率化(2)Androidリリース作業の効率化(2)
Androidリリース作業の効率化(2)
 
Groovy, Transforming Language
Groovy, Transforming LanguageGroovy, Transforming Language
Groovy, Transforming Language
 
Spock Framework
Spock FrameworkSpock Framework
Spock Framework
 
Testing Web Applications with GEB
Testing Web Applications with GEBTesting Web Applications with GEB
Testing Web Applications with GEB
 
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume LaforgeGroovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
 
function list
function listfunction list
function list
 
レガシーコード改善はじめました 横浜道場
レガシーコード改善はじめました 横浜道場レガシーコード改善はじめました 横浜道場
レガシーコード改善はじめました 横浜道場
 
Gradle a new Generation Build Tool
Gradle a new Generation Build ToolGradle a new Generation Build Tool
Gradle a new Generation Build Tool
 
Jenkinsを用いたAndroidアプリビルド作業効率化
Jenkinsを用いたAndroidアプリビルド作業効率化Jenkinsを用いたAndroidアプリビルド作業効率化
Jenkinsを用いたAndroidアプリビルド作業効率化
 
GradleによるG*なビルドシステムの構築
GradleによるG*なビルドシステムの構築GradleによるG*なビルドシステムの構築
GradleによるG*なビルドシステムの構築
 
Groovy Testing Aug2009
Groovy Testing Aug2009Groovy Testing Aug2009
Groovy Testing Aug2009
 
AgileJapan2010 基調講演:野中郁次郎先生による「実践知のリーダシップ~スクラムと知の場作り」
AgileJapan2010 基調講演:野中郁次郎先生による「実践知のリーダシップ~スクラムと知の場作り」AgileJapan2010 基調講演:野中郁次郎先生による「実践知のリーダシップ~スクラムと知の場作り」
AgileJapan2010 基調講演:野中郁次郎先生による「実践知のリーダシップ~スクラムと知の場作り」
 
Spock Framework 2
Spock Framework 2Spock Framework 2
Spock Framework 2
 
Groovier testing with Spock
Groovier testing with SpockGroovier testing with Spock
Groovier testing with Spock
 
Groovy 1.8の新機能について
Groovy 1.8の新機能についてGroovy 1.8の新機能について
Groovy 1.8の新機能について
 
Gradle talk, Javarsovia 2010
Gradle talk, Javarsovia 2010Gradle talk, Javarsovia 2010
Gradle talk, Javarsovia 2010
 
うさぎ組 in G* WorkShop -うさみみの日常-
うさぎ組 in G* WorkShop -うさみみの日常-うさぎ組 in G* WorkShop -うさみみの日常-
うさぎ組 in G* WorkShop -うさみみの日常-
 
The outlineoftestprocess
The outlineoftestprocessThe outlineoftestprocess
The outlineoftestprocess
 
Jenkins導入ライブ
Jenkins導入ライブJenkins導入ライブ
Jenkins導入ライブ
 

Similar to Spock: A Highly Logical Way To Test

Gradleintroduction 111010130329-phpapp01
Gradleintroduction 111010130329-phpapp01Gradleintroduction 111010130329-phpapp01
Gradleintroduction 111010130329-phpapp01Tino Isnich
 
Oscon Java Testing on the Fast Lane
Oscon Java Testing on the Fast LaneOscon Java Testing on the Fast Lane
Oscon Java Testing on the Fast LaneAndres Almiray
 
The Future of JVM Languages
The Future of JVM Languages The Future of JVM Languages
The Future of JVM Languages VictorSzoltysek
 
Real world scala
Real world scalaReal world scala
Real world scalalunfu zhong
 
Cool Jvm Tools to Help you Test - Aylesbury Testers Version
Cool Jvm Tools to Help you Test - Aylesbury Testers VersionCool Jvm Tools to Help you Test - Aylesbury Testers Version
Cool Jvm Tools to Help you Test - Aylesbury Testers VersionSchalk Cronjé
 
Cool JVM Tools to Help You Test
Cool JVM Tools to Help You TestCool JVM Tools to Help You Test
Cool JVM Tools to Help You TestSchalk Cronjé
 
Atlassian Groovy Plugins
Atlassian Groovy PluginsAtlassian Groovy Plugins
Atlassian Groovy PluginsPaul King
 
10 Cool Facts about Gradle
10 Cool Facts about Gradle10 Cool Facts about Gradle
10 Cool Facts about GradleEvgeny Goldin
 
BDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
BDD - Behavior Driven Development Webapps mit Groovy Spock und GebBDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
BDD - Behavior Driven Development Webapps mit Groovy Spock und GebChristian Baranowski
 
Using the Groovy Ecosystem for Rapid JVM Development
Using the Groovy Ecosystem for Rapid JVM DevelopmentUsing the Groovy Ecosystem for Rapid JVM Development
Using the Groovy Ecosystem for Rapid JVM DevelopmentSchalk Cronjé
 
Csmr2012 bettenburg presentation
Csmr2012 bettenburg presentationCsmr2012 bettenburg presentation
Csmr2012 bettenburg presentationSAIL_QU
 
Spocktacular Testing - Russel Winder
Spocktacular Testing - Russel WinderSpocktacular Testing - Russel Winder
Spocktacular Testing - Russel WinderJAXLondon2014
 
Spocktacular Testing
Spocktacular TestingSpocktacular Testing
Spocktacular TestingRussel Winder
 
Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018
Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018
Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018Codemotion
 
Beyond parallelize and collect - Spark Summit East 2016
Beyond parallelize and collect - Spark Summit East 2016Beyond parallelize and collect - Spark Summit East 2016
Beyond parallelize and collect - Spark Summit East 2016Holden Karau
 

Similar to Spock: A Highly Logical Way To Test (20)

Gradle Introduction
Gradle IntroductionGradle Introduction
Gradle Introduction
 
Gradleintroduction 111010130329-phpapp01
Gradleintroduction 111010130329-phpapp01Gradleintroduction 111010130329-phpapp01
Gradleintroduction 111010130329-phpapp01
 
Oscon Java Testing on the Fast Lane
Oscon Java Testing on the Fast LaneOscon Java Testing on the Fast Lane
Oscon Java Testing on the Fast Lane
 
Spock
SpockSpock
Spock
 
The Future of JVM Languages
The Future of JVM Languages The Future of JVM Languages
The Future of JVM Languages
 
Real world scala
Real world scalaReal world scala
Real world scala
 
Cool Jvm Tools to Help you Test - Aylesbury Testers Version
Cool Jvm Tools to Help you Test - Aylesbury Testers VersionCool Jvm Tools to Help you Test - Aylesbury Testers Version
Cool Jvm Tools to Help you Test - Aylesbury Testers Version
 
Cool JVM Tools to Help You Test
Cool JVM Tools to Help You TestCool JVM Tools to Help You Test
Cool JVM Tools to Help You Test
 
Unit testing
Unit testingUnit testing
Unit testing
 
Atlassian Groovy Plugins
Atlassian Groovy PluginsAtlassian Groovy Plugins
Atlassian Groovy Plugins
 
10 Cool Facts about Gradle
10 Cool Facts about Gradle10 Cool Facts about Gradle
10 Cool Facts about Gradle
 
BDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
BDD - Behavior Driven Development Webapps mit Groovy Spock und GebBDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
BDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
 
Using the Groovy Ecosystem for Rapid JVM Development
Using the Groovy Ecosystem for Rapid JVM DevelopmentUsing the Groovy Ecosystem for Rapid JVM Development
Using the Groovy Ecosystem for Rapid JVM Development
 
Csmr2012 bettenburg presentation
Csmr2012 bettenburg presentationCsmr2012 bettenburg presentation
Csmr2012 bettenburg presentation
 
Spocktacular Testing - Russel Winder
Spocktacular Testing - Russel WinderSpocktacular Testing - Russel Winder
Spocktacular Testing - Russel Winder
 
Spocktacular Testing
Spocktacular TestingSpocktacular Testing
Spocktacular Testing
 
Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018
Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018
Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018
 
Exception Handling in Scala
Exception Handling in ScalaException Handling in Scala
Exception Handling in Scala
 
Spock
SpockSpock
Spock
 
Beyond parallelize and collect - Spark Summit East 2016
Beyond parallelize and collect - Spark Summit East 2016Beyond parallelize and collect - Spark Summit East 2016
Beyond parallelize and collect - Spark Summit East 2016
 

More from Howard Lewis Ship

Backbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The BrowserBackbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The BrowserHoward Lewis Ship
 
Modern Application Foundations: Underscore and Twitter Bootstrap
Modern Application Foundations: Underscore and Twitter BootstrapModern Application Foundations: Underscore and Twitter Bootstrap
Modern Application Foundations: Underscore and Twitter BootstrapHoward Lewis Ship
 
Have Your Cake and Eat It Too: Meta-Programming Techniques for Java
Have Your Cake and Eat It Too: Meta-Programming Techniques for JavaHave Your Cake and Eat It Too: Meta-Programming Techniques for Java
Have Your Cake and Eat It Too: Meta-Programming Techniques for JavaHoward Lewis Ship
 
Clojure: Towards The Essence Of Programming (What's Next? Conference, May 2011)
Clojure: Towards The Essence Of Programming (What's Next? Conference, May 2011)Clojure: Towards The Essence Of Programming (What's Next? Conference, May 2011)
Clojure: Towards The Essence Of Programming (What's Next? Conference, May 2011)Howard Lewis Ship
 
Arduino: Open Source Hardware Hacking from the Software Nerd Perspective
Arduino: Open Source Hardware Hacking from the Software Nerd PerspectiveArduino: Open Source Hardware Hacking from the Software Nerd Perspective
Arduino: Open Source Hardware Hacking from the Software Nerd PerspectiveHoward Lewis Ship
 
Practical Clojure Programming
Practical Clojure ProgrammingPractical Clojure Programming
Practical Clojure ProgrammingHoward Lewis Ship
 
Clojure: Towards The Essence of Programming
Clojure: Towards The Essence of ProgrammingClojure: Towards The Essence of Programming
Clojure: Towards The Essence of ProgrammingHoward Lewis Ship
 
Tapestry 5: Java Power, Scripting Ease
Tapestry 5: Java Power, Scripting EaseTapestry 5: Java Power, Scripting Ease
Tapestry 5: Java Power, Scripting EaseHoward Lewis Ship
 
Brew up a Rich Web Application with Cappuccino
Brew up a Rich Web Application with CappuccinoBrew up a Rich Web Application with Cappuccino
Brew up a Rich Web Application with CappuccinoHoward Lewis Ship
 
Clojure: Functional Concurrency for the JVM (presented at OSCON)
Clojure: Functional Concurrency for the JVM (presented at OSCON)Clojure: Functional Concurrency for the JVM (presented at OSCON)
Clojure: Functional Concurrency for the JVM (presented at OSCON)Howard Lewis Ship
 
Tapestry: State of the Union
Tapestry: State of the UnionTapestry: State of the Union
Tapestry: State of the UnionHoward Lewis Ship
 
Clojure: Functional Concurrency for the JVM (presented at Open Source Bridge)
Clojure: Functional Concurrency for the JVM (presented at Open Source Bridge)Clojure: Functional Concurrency for the JVM (presented at Open Source Bridge)
Clojure: Functional Concurrency for the JVM (presented at Open Source Bridge)Howard Lewis Ship
 

More from Howard Lewis Ship (16)

Backbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The BrowserBackbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The Browser
 
Modern Application Foundations: Underscore and Twitter Bootstrap
Modern Application Foundations: Underscore and Twitter BootstrapModern Application Foundations: Underscore and Twitter Bootstrap
Modern Application Foundations: Underscore and Twitter Bootstrap
 
Have Your Cake and Eat It Too: Meta-Programming Techniques for Java
Have Your Cake and Eat It Too: Meta-Programming Techniques for JavaHave Your Cake and Eat It Too: Meta-Programming Techniques for Java
Have Your Cake and Eat It Too: Meta-Programming Techniques for Java
 
Clojure: Towards The Essence Of Programming (What's Next? Conference, May 2011)
Clojure: Towards The Essence Of Programming (What's Next? Conference, May 2011)Clojure: Towards The Essence Of Programming (What's Next? Conference, May 2011)
Clojure: Towards The Essence Of Programming (What's Next? Conference, May 2011)
 
Arduino: Open Source Hardware Hacking from the Software Nerd Perspective
Arduino: Open Source Hardware Hacking from the Software Nerd PerspectiveArduino: Open Source Hardware Hacking from the Software Nerd Perspective
Arduino: Open Source Hardware Hacking from the Software Nerd Perspective
 
Practical Clojure Programming
Practical Clojure ProgrammingPractical Clojure Programming
Practical Clojure Programming
 
Clojure: Towards The Essence of Programming
Clojure: Towards The Essence of ProgrammingClojure: Towards The Essence of Programming
Clojure: Towards The Essence of Programming
 
Codemash-Clojure.pdf
Codemash-Clojure.pdfCodemash-Clojure.pdf
Codemash-Clojure.pdf
 
Codemash-Tapestry.pdf
Codemash-Tapestry.pdfCodemash-Tapestry.pdf
Codemash-Tapestry.pdf
 
Tapestry 5: Java Power, Scripting Ease
Tapestry 5: Java Power, Scripting EaseTapestry 5: Java Power, Scripting Ease
Tapestry 5: Java Power, Scripting Ease
 
Brew up a Rich Web Application with Cappuccino
Brew up a Rich Web Application with CappuccinoBrew up a Rich Web Application with Cappuccino
Brew up a Rich Web Application with Cappuccino
 
Clojure Deep Dive
Clojure Deep DiveClojure Deep Dive
Clojure Deep Dive
 
Clojure: Functional Concurrency for the JVM (presented at OSCON)
Clojure: Functional Concurrency for the JVM (presented at OSCON)Clojure: Functional Concurrency for the JVM (presented at OSCON)
Clojure: Functional Concurrency for the JVM (presented at OSCON)
 
Cascade
CascadeCascade
Cascade
 
Tapestry: State of the Union
Tapestry: State of the UnionTapestry: State of the Union
Tapestry: State of the Union
 
Clojure: Functional Concurrency for the JVM (presented at Open Source Bridge)
Clojure: Functional Concurrency for the JVM (presented at Open Source Bridge)Clojure: Functional Concurrency for the JVM (presented at Open Source Bridge)
Clojure: Functional Concurrency for the JVM (presented at Open Source Bridge)
 

Recently uploaded

How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
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
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
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
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfhans926745
 

Recently uploaded (20)

How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
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
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
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
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdf
 

Spock: A Highly Logical Way To Test

  • 1. Spock: A Highly Logical Way To Test Howard M. Lewis Ship TWD Consulting hlship@gmail.com @hlship © 2012 Howard M. Lewis Ship
  • 2. Why Don't We Test? Hard To Get Started My Code's Perfect Code Too Monolithic Tests Broke, Nobody Fixed, Turned Off Uh, We Used To? More Code Is More Code Test Code Hard To Maintain
  • 3. What if ... Test code was readable? Tests were concise? Test reports were useful? Failures were well described? Mocking was easy? … wouldn't that be most logical?
  • 4. My Path Wrote own test framework – 1990's in PL/1 – 5000 - 7000 tests First JUnit tests (Tapestry 2001 template parser) 2003-ish Started using TestNG 2004-ish Started using EasyMock 2005-ish Started using Selenium 1 2006-ish Dabbled in Groovy 2010 Spock! ~ 0.4
  • 5. Terminology Fixture Specification Collaborator System Feature Feature Under Specification Collaborator
  • 6. First Specification sp o SkySpecification.groovy gro ck 0 ov . package org.example y-1 6- .8 import spock.lang.* class SkySpecification extends Specification { ... } All Specifications extend from this base class Sky.java package org.example.sus; public class Sky { public String getColor() { return "blue"; } }
  • 7. Feature Methods def "sky is blue"() { setup: def sky = new Sky() expect: sky.color == "blue" }
  • 8. Execution $ gradle test Note: the Gradle build daemon is an experimental feature. As such, you may experience unexpected build failures. You may need to occasionally stop the daemon. :compileJava UP-TO-DATE :compileGroovy UP-TO-DATE :processResources UP-TO-DATE :classes UP-TO-DATE :compileTestJava UP-TO-DATE :compileTestGroovy $ tree build/reports/ :processTestResources UP-TO-DATE build/reports/ :testClasses └── tests :test ├── base-style.css ├── css3-pie-1.0beta3.htc BUILD SUCCESSFUL ├── index.html ├── org.example.SkySpecification.html Total time: 3.831 secs ├── org.example.html ~/workspaces/github/spock-examples ├── report.js $ └── style.css 1 directory, 7 files ~/workspaces/github/spock-examples $
  • 9.
  • 10.
  • 11.
  • 13.
  • 14.
  • 15. Feature Method Blocks def "sky is blue"() { setup: def sky = new Sky() expect: sky.color == "blue" } setup: or given: expect: when: then: where: cleanup: Feature methods must contain at least one block otherwise, not a feature method
  • 16. setup: Initialization of the fixture Always at top of method Can't be repeated Can be given: instead Anything up to first label is implicit setup:
  • 17. expect: Response expect: sky.color == "blue" Stimulus Combines stimulus and response Contains only conditions and variable definitions Conditions assert Groovy truth Best for purely functional (no-side effects) functions
  • 18. when: / then: def "clouds are grey"() { def sky = new Sky() when: Stimulus sky.addStormSystem() then: sky.color == "grey" Response } Used as a pair Tests method with side effects then: may only contain conditions, exception conditions, interactions and variable definitions
  • 19. when: / then: def "clouds are grey"() { def sky = new Sky() when: sky.addStormSystem() then: sky.color == "grey" }
  • 20. Test driven Sky.java package org.example.sus; public class Sky { private String color = "blue"; public String getColor() { return color; } public void addStormSystem() { color = "grey"; } }
  • 21. then: Old Values def "pushing an element on the stack increases its size by one"() {   def stack = new Stack()   when: stack.push("element")   then: stack.size() == old(stack.size()) + 1 } Expression value captured before where: block
  • 22. Extended Assert def "use of extended assert"() { expect: assert 4 == 5, "Big Brother says there are four fingers" }
  • 23. cleanup: setup: def file = new File("/some/path") file.createNewFile() // ... cleanup: file.delete() Cleanup external resources Always invoked, even if previous exceptions
  • 24. where: def "length of crew member names"() { expect: name.length() == length where: name     | length "Spock"  | 5 "Kirk"   | 4 "Scotty" | 6 } Parameterizes feature method with data Must be last block Can use | or || as separator
  • 25. where: One entry for three feature method executions
  • 26. where: using lists def "length of crew member names (using lists)"() { expect: name.length() == length where: name << ["Spock", "Kirk", "Scotty"] length << [5, 4, 6] } Could come from external file or database where: [name, age, gender] = sql.execute("select name, age, sex from ⏎ customer")
  • 27. where: derived values def "length of crew member names (with derived values)"() { expect: name.length() == length where: name << ["Spock", "Kirk", "Scotty"] length = name.length() }
  • 28. Block labels def "clouds are grey"() { given: "A fresh Sky" def sky = new Sky() when: "A storm system rolls in" sky.addStormSystem() then: "It all goes grey" sky.color == "grey" } Allowed, but not (currently) used and: "block" allowed, does nothing
  • 30. Fields package org.example import org.example.sus.Sky import spock.lang.Specification class SkySpecification extends Specification { def sky = new Sky() New for each feature method def "sky is blue by default"() { expect: sky.color == "blue" } def "clouds are grey"() { given: "A fresh Sky" when: "A storm system rolls in" sky.addStormSystem() then: "It all goes grey" sky.color == "grey" } }
  • 31. Shared Fields Created once, shared across all instances class MySpecification extends Specification { @Shared def resource = new AnExepensiveResource() static final PASSWORD = "sayfriendandenter" … } Statics should be final and immutable
  • 32. Fixture Methods def setup() { … } def cleanup() { … } Create / initialize instance of Specification Invoke setup() Invoke feature method Invoke cleanup()
  • 33. Fixture Methods def setupSpec() { … } def cleanupSpec() { … } Instance created for Specification setup / cleanup May only access @Shared and static fields
  • 34. Exception Conditions def ins = new ClassInstantiatorImpl(ContextCatcher, ⏎ ContextCatcher.constructors[0], null) def "may not add a duplicate instance context value"() { given: def ins2 = ins.with(String, "initial value") when: ins2.with(String, "conflicting value") then: def e = thrown() Or: e = thrown(IllegalStateException) e.message == "An instance context value of type java.lang.String ⏎ has already been added." }
  • 35. Typed Exceptions def ins = new ClassInstantiatorImpl(ContextCatcher, ⏎ ContextCatcher.constructors[0], null) def "may not add a duplicate instance context value"() { given: def ins2 = ins.with(String, "initial value") when: ins2.with(String, "conflicting value") then: IllegalStateException e = thrown() e.message == "An instance context value of type java.lang.String ⏎ has already been added." }
  • 36. notThrown() def "HashMap accepts null key"() {   setup:   def map = new HashMap()     when:   map.put(null, "elem")     then:   notThrown(NullPointerException) } Documentation value only Also: noExceptionThrown()
  • 38. Fixture Specification Collaborator Feature SystemUnder Feature Specification Collaborator
  • 39. Configured System Instance Under Specification Mock Object
  • 40. Payment CustomerDAO Processor PaymentProcessor.groovy package org.example.sus class PaymentProcessor { CustomerDAO customerDAO def applyPayment(long customerId, BigDecimal amount) { Customer customer = customerDAO.getById(customerId) if (customer == null) throw new IllegalArgumentException("No customer #$customerId") customer.accountBalance += amount CustomerDAO.java package org.example.sus; customerDAO.update(customer) } public interface CustomerDAO { } Customer getById(long id); void update(Customer customer); }
  • 41. class ApplyPaymentSpecification extends Specification { CustomerDAO dao = Mock() Factory method PaymentProcessor processor def setup() { processor = new PaymentProcessor(customerDAO: dao) } … }|
  • 42. Defining Mock Behavior def "unknown customer id is an exception"() { when: processor.applyPayment(12345, 100) then: 1 * dao.getById(12345) >> null Define behavior for preceding when: block IllegalArgumentException e = thrown() e.message == "No customer #12345" }
  • 43. def "valid customer id for update"() { when: processor.applyPayment(customer.id, 200) then: 1 * dao.getById(customer.id) >> customer 1 * dao.update(customer) customer.accountBalance == 500 where: customer = new Customer(id: 98765, accountBalance: 300) }
  • 44. Target and Method Constraints Argument Constraints 1 * dao.getById(12345) >> null Number of invocations: Returns a value cardinality
  • 45. Cardinality Omitted ➠ Interaction is optional, must have return value n * mock.method(…) ➠ exactly n times (n.._) * mock.method(…) ➠ at least n times (_..n) * mock.method(…) ➠ Up to n times
  • 46. Argument Constraints _ ➠ Any argument *_ ➠ Any number of arguments !null ➠ Any non-null argument value ➠ Argument equals value !value ➠ Argument not equal to value _ as Type ➠ Non-null argument assignable to Type
  • 47. Closures for Argument Contraints class InteractionsSpecification extends Specification { Operation mock = Mock() interface Operation { Object op(input) } def isOdd(input) { input % 2 != 0 } Helper method def "closure for parameter constraint"() { when: assert mock.op(3) == 6 assert mock.op(7) == 14 then: (2..7) * mock.op({ isOdd(it) }) >> { 2 * it } } Return value computed by closure
  • 48. def "wrong number of invocations"() { when: assert mock.op(7) == 14 then: (2..7) * mock.op({ isOdd(it) }) >> { 2 * it } } Too few invocations for: (2..7) * mock.op({ result = 2 * it; return it % 2 != 0 }) >> { result } (1 invocation) & at org.spockframework.mock.InteractionScope.verifyInteractions(InteractionScope.java:66) & at org.spockframework.mock.MockController.leaveScope(MockController.java:35) & at org.example.InteractionsSpecification.wrong number of invocations(InteractionsSpecification.groovy:32)
  • 49. Mocks are Lenient def "parameter does not match closure constraint"() { when: assert mock.op(3) == 6 assert mock.op(4) == null assert mock.op(7) == 14 then: _ * mock.op({ isOdd(it) }) >> { 2 * it } }
  • 50. Less Lenient Mocks def "detecting parameter that doesn't match"() { when: assert mock.op(3) == 6 assert mock.op(4) == null assert mock.op(7) == 14 then: _ * mock.op({ isOdd(it) }) >> { 2 * it } 0 * _ aka "any interaction" } Too many invocations for: 0 * _ (1 invocation) Last invocation: mock.op(4) & at org.spockframework.mock.MockInteraction.accept(MockInteraction.java:58) & at org.spockframework.mock.MockInteractionDecorator.accept(MockInteractionDecorator.java:41) & at org.spockframework.mock.InteractionScope$1.accept(InteractionScope.java:38) & at org.spockframework.mock.MockController.dispatch(MockController.java:42) & at org.spockframework.mock.DefaultMockFactory$1.invoke(DefaultMockFactory.java:70) & at org.example.InteractionsSpecification.detecting parameter that doesn't match(InteractionsSpecification.groovy:58)
  • 51. Target and Method Constraints Target Constraint 1 * dao.getById(12345) >> null Method Constraint
  • 52. Target Constraints name ➠ Match the mock in the variable or field _ ➠ Match any mock
  • 53. Method Constraints name ➠ Match method with given name /re/ ➠ Match methods matching regular expression ➠ e.g. bean./set.*/(_) _ ➠ Match any method
  • 54. Return Values >> value ➠ Return the value >> { … } ➠ Evaluate the closure and return the result >>> [ a, b, c] ➠ Return a, then return b, then keep returning c ➠ Any kind of iterable list, any size
  • 55. Chained Return Values then: service.getStatus() >>> ["ok", "ok", "fail"] >> { throw new RuntimeException("Status failure."); } The last value sticks
  • 56. Ordered Interactions def "test three amigos"() { when: facade.doSomething() then: 1 * collab1.firstPart() No order checking 1 * collab2.secondPart() on firstPart(), secondPart() then: 1 * collab3.thirdPart() } thirdPart() only allowed after both firstPart(), secondPart()
  • 57. Stubbing def "frobs the gnop"() { A "global interaction" checker.isValid(_) >> true valid to end of when: method … }
  • 59. @Unroll @Unroll def "Crew member '#name' length is #length"() { expect: name.length() == length where: name | length "Spock" | 5 "Kirk" | 4 "Scotty" | 6 }
  • 60.
  • 61. @Unroll class CanonicalWhereBlockExampleSpecification extends Specification { def "Crew member '#name' length is #length"() { … } def "length of crew member names (using lists)"() { … } def "length of crew member names (with derived values)"() { … } }
  • 62. @Timeout @Timeout(5) def "can access data in under five seconds"() { … } @Timeout(value=100, unit=TimeUnit.MILLISECONDS) def "can update data in under 100 ms"() { … } Feature and fixture methods run on main thread A second thread may interrupt the main thread Can be placed on class to affect all feature methods
  • 63. @Stepwise @Stepwise class BuildingBlocksSpecification extends Specification { def "first step()" { … } def "second step"() { … } def "third step"() { … } Feature methods run in declaration order Failed methods cause remainder to be skipped
  • 64. @AutoCleanup def DatabaseSpecification … { @AutoCleanup @Shared Connection connection … } Will invoke close() on field's value Exceptions are reported but are not failures quiet=true ➠ Don't report exceptions value attribute is name of method to invoke
  • 65. @Ignore / @IgnoreRest Used to temporarily control which feature methods execute @Ignore ➠ Ignore this method, run others @IgnoreRest ➠ Run this method, ignore others
  • 72. Q&A