Loading presentation...

Present Remotely

Send the link below via email or IM

Copy

Present to your audience

Start remote presentation

  • Invited audience members will follow you as you navigate and present
  • People invited to a presentation do not need a Prezi account
  • This link expires 10 minutes after you close the presentation
  • A maximum of 30 users can follow your presentation
  • Learn more about this feature in our knowledge base article

Do you really want to delete this prezi?

Neither you, nor the coeditors you shared it with will be able to recover it again.

DeleteCancel

Make your likes visible on Facebook?

Connect your Facebook account to Prezi and let your likes appear on your timeline.
You can change this under Settings & Account at any time.

No, thanks

Groovier BDD with Spock

No description
by

Michał Kordas

on 16 June 2015

Comments (0)

Please log in to add your comment.

Report abuse

Transcript of Groovier BDD with Spock

Groovier BDD with Spock
given: // setup phase (optional)

when: // stimulus phase

then: // response phase

where: // parametrizations (optional)
Only developers write story files
Business people don't read story files
Solution
Developers can
read and understand code

JUnit
to describe system behavior
JBehave
Tool designed for non developers ends up being used only by developers...
@Test
public void shouldDoSomethingWhenSomethingHappens() throws Exception
{
//given

//when

//then
}
@Test
public void receiveSentMessage() throws InterruptedException, IOException {
givenMessageIsSentTrhoughConfiguredChannel();
whenTheMessageIsRetrivedFromTheChannel();
thenTheReceivedMessageShouldMatchTheSentMessage();
}
@RunWith(Theories.class)
public class TestCellTransitions {

@DataPoints
public static int[] input = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 };

@Test
public void liveCellWithZeroNeighboursDies
assertThat(LIVE.mutate(0), is(DEAD));
}

@Theory
public void liveCellWithFewerThanTwoLiveNeighboursDies(int liveNeighbours) {
assumeThat(liveNeighbours, lessThan(2));
assertThat(LIVE.mutate(liveNeighbours), is(DEAD));
}

@Theory
public void liveCellWithTwoOrThreeLiveNeighboursLivesOnToTheNextGeneration
(int liveNeighbours) {
assumeThat(liveNeighbours, anyOf(is(2), is(3)));
assertThat(LIVE.mutate(liveNeighbours), is(LIVE));
}

@Theory
public void liveCellWithMoreThanThreeLiveNeighboursDies(int liveNeighbours) {
assumeThat(liveNeighbours, greaterThan(3));
assertThat(LIVE.mutate(liveNeighbours), is(DEAD));
}
}
Given a live cell
When it has 0 live neighbours
Then the cell dies
When it has 1 live neighbour
Then the cell dies
When it has 2 live neighbours
Then the cell lives on to the next generation
When it has 3 live neighbours
Then the cell lives on to the next generation
When it has 4 live neighbours
Then the cell dies
'If tests do not comprehensively describe the behavior of your system, then they are lulling you into a false sense of security.'
Groovy Language
Dynamic language
but statically type checked and compiled if needed
Native syntax for
lists and maps
List<Integer> list = [1, 2, 3, 4, 5]
As little punctuation as possible
optional semicolons
optional parentheses
optional dots when chaining method calls
Optionally and strong typed
Software that realizes
purposes...
goals...
aims...
Software that matters
This is NOT rocket science
The only problem...
... is to understand the problem
BDD
set of preconditions
when an event occurs
testable outcome is achieved
given
when
then
Requirements
understandable to developer
understandable to business
unambiguous
automated
run frequently
Weakly typed
Strongly typed
Statically typed
Dynamically typed
Java
Groovy
C++
JavaScript

Map<String, Integer> map = [first: 1, second: 2]
Poor IDE support
Regexp matching
the enterprise ready specification framework
for testing Java and Groovy applications
Easy to learn
Assertion API based on operators
Detailed failure information
Focus on specifying behavior
Suitable for all kinds of testing
Leverages Groovy goodness
Minimalistic mocking API based on operators
No annotations on every method
max(a, b) == c
| | | | |
3 1 3 | 2
false
Focus on domain language
Nice and compact testing language
unit
TDD
BDD
system
acceptance
integration
test-first
test-last
Based on JUnit
Spock?
Spec + Mock
SUT -> SUS
System Under Test
System Under Spec
Specification
class ReportGeneration extends Specification {


any suitable name

}
Feature method
def 'Report is generated for AMEND message' {


any unicode name for a scenario

}
Blocks
expect: // stimulus and response
or just

Data-driven Testing
First-class data tables
def "maximum of two numbers"() {
expect:
Math.max(a, b) == c

where:
a | b | c
2 | 3 | 3
7 | 4 | 8
5 | 5 | 5
}
maximum of two numbers[0] PASSED
maximum of two numbers[1] FAILED

Math.max(a, b) == c
| | | | |
| 7 4 | 8
7 false

maximum of two numbers[2] PASSED
Unrolling
Parametrized method names
import static Math.max

class Maths extends Specification {

def "maximum of #a and #b is #c"() {
expect:
max(a, b) == c

where:
a | b | c
2 | 3 | 3
7 | 4 | 8
5 | 5 | 5
}
}
maximum of 2 and 3 is 3 PASSED
maximum of 7 and 4 is 8 FAILED

Math.max(a, b) == c
| | | | |
| 7 4 | 8
7 false

maximum of 5 and 5 is 5 PASSED
Cardinality
1 * subscriber.receive("hello") // exactly one call
0 * subscriber.receive("hello") // zero calls
(1..3) * subscriber.receive("hello") // between one and three calls
(1.._) * subscriber.receive("hello") // at least one call
(_..3) * subscriber.receive("hello") // at most three calls
Method constraint
1 * subscriber.receive("hello") // a method named 'receive'

1 * subscriber./r.*e/("hello") // a method whose name matches the given regular expression
Argument constraints
1 * subscriber.receive("hello") // an argument that is equal to "hello"
1 * subscriber.receive(!"hello") // an argument that is unequal to "hello"
1 * subscriber.receive() // the empty argument list
1 * subscriber.receive(_) // any single argument (including null)
1 * subscriber.receive(*_) // any argument list ()
1 * subscriber.receive(!null) // any non-null argument
1 * subscriber.receive(_ as String) // any non-null argument that is-a String
1 * subscriber.receive({ it.size() > 3 }) // must satisfy the given predicate
Define Mock
Subscriber subscriber = Mock()
Mocking
publisher.subscribers << subscriber
Inject Mock
subscriber.receive("hello") >> "ok"
Record Mock
Title
@Title("This is easy to read")
class ThisIsHarderToReadSpec extends Specification {
...
}
Narrative
@Narrative('''
As a user
I want foo
So that bar
''')
class GiveTheUserFooSpec() { ... }
Failure conditions
when:
a message is sent

then:
thrown MessageNotSentException
Textual descriptions
given: 'an AMEND message'
message =
aMessage
(AMEND)

when: 'the message is sent'
send
(message)

then: 'a report is generated with NEW event type'
report =
receiveReportFor
(message)
report.eventType == AMEND
Next level
given:
message = aMessage(eventType: NEW)

when:
SUS.receives message

then:
SUS.generates report
report.eventType == NEW
Even Next level
given NEW trade message
when: the message is sent to SUS
then: a report is generated and report.status == N
given NEW message
when the message is sent SUS
then a report is generated
and report has status set to N
How can we guarantee that?
Gherkin language
Creator of JBehave framework
Dull story files
to find corresponding code for each step
.*
Parameter converters
work for monkeys
Only for system-level
Painflul refactoring
SHIFT+F6 doesn't work...
and they dislike it...
Twice as much files to maintain
and these files are tightly coupled...
JUnit
JBehave
???
1/"2" = ???
Created to work with JAVA
99% Java code is valid Groovy code
Public by default
The power of switch
Getters and Setters
take(coffee).with(sugar, chocolate).and(milk);
take coffee with sugar, chocolate and milk
Groovy Truth
Fancy operators
Does it compile?
public class DoesItCompile {
public static void main(String... args) {
http://spockframework.org
System.out.println("Hello world");
}
}
Real Life
Documentation generation
MichałKordas, QA, Luxoft
Full transcript