SlideShare ist ein Scribd-Unternehmen logo
1 von 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

Weitere ähnliche Inhalte

Was ist angesagt?

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
 

Was ist angesagt? (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
 

Andere mochten auch

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
 

Andere mochten auch (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導入ライブ
 

Ähnlich wie 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
 

Ähnlich wie 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
 

Mehr von 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
 

Mehr von 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)
 

Kürzlich hochgeladen

Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostZilliz
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfSeasiaInfotech2
 

Kürzlich hochgeladen (20)

Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdf
 

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