spockframework / spock

The Enterprise-ready testing and specification framework.
https://spockframework.org
Apache License 2.0
3.55k stars 468 forks source link

States for interaction #252

Open robfletcher opened 9 years ago

robfletcher commented 9 years ago

Originally reported on Google Code with ID 130

Need some way of ordering interactions not based in strict order of declaration of 'then'
blocks. An ordering based on 'states' is needed in some scenarios. 

This mechanism is very useful to test interaction generated by a stateful object.

Of course perhaps it is yet implemented in Spock but not documented. If this is the
case some samples would be useful.

Reported by eamodeorubio on 2010-10-07 10:51:20

robfletcher commented 9 years ago
Spock doesn't support this feature at the moment. How often do you have a need for it?
Do you currently use JMock for this, and have you considered using JMock together with
Spock for when you need this feature?

Reported by pniederw on 2010-10-07 20:23:44

robfletcher commented 9 years ago
I need this feature in about 15% of my tests.
As I've worked with jmock several years it won't be a problem to mix it with spock.
But I'd prefer to have support for this feature in spock to use a single test framework
 I like very much spock but I think this feature is important.

Reported by eamodeorubio on 2010-10-08 06:59:33

robfletcher commented 9 years ago
I think that using jmock for some tests scenarios and spock for others would be confusing
and difficult to understand. That's why I'd only consider this solution as a last ressort.

There is no need to implement "states" in the same way as JMock but only to provide
an equivalent functionality.

I've been thinking about implementing "states" using "spock's way". Perhaps a good
approach is not to implement "states", but to introduce preconditions and actions to
interactions. This can implement the "states" feature and give more flexibility and
power to spock's interaction, which is good for unforeseen future needs. So, using
this hypothetic "preconditions" and "actions", we can implement "states", with some
code like the following:
then: 
  interaction {
    def state="some state";
    [state == "some state"] 1 * someObject.someMethod(paramMatcher) { actualParamValue
-> state = "other state"; return "mocked method return value"; }
    [state == "other state" ] 1 * otherObject.otherMethod(_) >> returnValue
  }
The optional "[ some assert ]" block could act as a precondition that must be true
to accept the interaction. 
The "closure" can define an action, which is executed if expectations are met for the
interaction. The action can perform any code and optionally return a value as result
for the mocked method. In fact you can now use a closure to define a parameter matcher,
so it makes sense to use it to define an action.

Reported by eamodeorubio on 2010-10-08 12:21:55

robfletcher commented 9 years ago
Thanks for the proposal, we'll consider it. By the way, actions are already supported:

1 * foo.bar(baz) >> { arg -> doSomething(arg) }

Reported by pniederw on 2010-10-08 12:30:29

robfletcher commented 9 years ago
Ok, thank you. Didn't know that actions were implemented. So, in fact, there is only
need to implement "preconditions" to have "states".

Reported by eamodeorubio on 2010-10-08 12:34:45

robfletcher commented 9 years ago
I'm trying to come up with a syntax for "preconditions". Since we already have "interaction
{ ... }", how do you like the following?

def state = "on" // can use any variable

interaction(state: "on") {
  device.powerOff() >> { state = "off" }
  ...
}                                      

interaction(state: "off") {
  device.powerOn() >> { state = "on" }
  ...
}     

Reported by pniederw on 2010-11-03 03:13:29

robfletcher commented 9 years ago
Nice ! I like it.

Reported by eamodeorubio on 2010-11-03 18:41:46