Tools, techniques and reflections
BDD-Driven Microservices
in Java
John
Ferguson
Smart
Introductions
“I help teams of smart people 

learn to work together more efficiently, 

to deliver better software faster”
Independently
Deployable
Bounded ContextsLoosely CoupledSingle
Responsibility
Microservices 101
Independently
Deployable
Bounded ContextsLoosely CoupledSingle
Responsibility
Microservices 101
Independently
Deployable
Bounded ContextsLoosely CoupledSingle
Responsibility
Microservices 101
Independently
Deployable
Bounded ContextsLoosely CoupledSingle
Responsibility
Microservices 101
Independently
Deployable
Bounded ContextsLoosely CoupledSingle
Responsibility
Microservices 101
Independently
Deployable
Bounded ContextsLoosely CoupledSingle
Responsibility
Microservices 101
Microservices 101
Movie Catalog
Service
Authentication
Service
Shopping Cart
Service
Delivery
Service
Payment
Service
REST/HTTP
Microservices 101
Movie Catalog
Service
Authentication
Service
Shopping Cart
Service
Delivery
Service
Payment
Service
Event Bus
Microservices 101
Movie Catalog Service
Microservices 101
Movie Catalog Service
Resource
Microservices 101
Movie Catalog Service
Resource
Service Layer
Domain model
Repositories
Microservices 101
Movie Catalog Service
Resource
Persistance Layer
Service Layer
Domain model
Repositories
Microservices 101
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
The testing pyramid
The testing pyramid
Unit Tests
The testing pyramid
Unit Tests
Integration Tests
The testing pyramid
Unit Tests
Integration Tests
End-to-end Tests
The testing pyramid
Unit Tests
Integration Tests
End-to-end Tests
The testing pyramid
Unit Tests
Integration Tests
End-to-end Tests
The testing pyramid
Unit Tests
Integration Tests
End-to-end Tests
The testing pyramid
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Unit Tests
The testing pyramid
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Unit Tests
The testing pyramid
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Unit Tests
The testing pyramid
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Unit Tests
The testing pyramid
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Unit Tests
The testing pyramid
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Unit Tests
The testing pyramid
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Unit Tests
The testing pyramid
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Unit Tests
The testing pyramid
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Unit Tests
The testing pyramid
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Integration
Tests
The testing pyramid
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Integration
Tests
The testing pyramid
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Integration
Tests
The testing pyramid
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Integration
Tests
The testing pyramid
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Integration
Tests
The testing pyramid End-to-End
Tests
Movie Catalog
Service
Authentication
Service
Shopping Cart
Service
Delivery
Service
Payment
Service
Event Bus
The testing pyramid End-to-End
Tests
Movie Catalog
Service
Authentication
Service
Shopping Cart
Service
Delivery
Service
Payment
Service
Event Bus
The testing pyramid End-to-End
Tests
Movie Catalog
Service
Authentication
Service
Shopping Cart
Service
Delivery
Service
Payment
Service
Event Bus
The testing pyramid End-to-End
Tests
Movie Catalog
Service
Authentication
Service
Shopping Cart
Service
Delivery
Service
Payment
Service
Event Bus
The testing pyramid End-to-End
Tests
Movie Catalog
Service
Authentication
Service
Shopping Cart
Service
Delivery
Service
Payment
Service
Event Bus
The testing pyramid End-to-End
Tests
Movie Catalog
Service
Authentication
Service
Shopping Cart
Service
Delivery
Service
Payment
Service
Event Bus
The testing pyramid End-to-End
Tests
Movie Catalog
Service
Authentication
Service
Shopping Cart
Service
Delivery
Service
Payment
Service
Event Bus
The testing pyramid
Unit Tests
Integration Tests
End-to-end Tests
The testing pyramid
Unit Tests
Integration Tests
End-to-end Tests
The testing pyramid
Unit Tests
Integration Tests
End-to-end Tests
The testing pyramid
Unit Tests
Integration Tests
End-to-end Tests
The testing pyramid
Unit Tests
Integration Tests
End-to-end Tests
The testing pyramid
Unit Tests
Integration Tests
End-to-end Tests
The testing pyramid
Unit Tests
Integration Tests
End-to-end Tests
The testing pyramid
Unit Tests
Integration Tests
End-to-end Tests
The testing pyramid
Unit Tests
Integration Tests
End-to-end Tests
The testing pyramid
Unit Tests
Integration Tests
End-to-end Tests
The testing pyramid
Unit Tests
Integration Tests
End-to-end Tests
To document how
to interact with the
microservice
To document what
the microservice
does
To ensure the
service work
correctly
To ensure we
are delivering
valuable
functionality
Why test our micro-services?
To document how
to interact with the
microservice
To document what
the microservice
does
To ensure the
service work
correctly
To ensure we
are delivering
valuable
functionality
Why test our micro-services?
To document how
to interact with the
microservice
To document what
the microservice
does
To ensure the
service work
correctly
To ensure we
are delivering
valuable
functionality
Why test our micro-services?
To document how
to interact with the
microservice
To document what
the microservice
does
To ensure the
service work
correctly
To ensure we
are delivering
valuable
functionality
Why test our micro-services?
To document how
to interact with the
microservice
To document what
the microservice
does
To ensure the
service work
correctly
To ensure we
are delivering
valuable
functionality
Why test our micro-services?
To document how
to interact with the
microservice
To document what
the microservice
does
To ensure the
service work
correctly
To ensure we
are delivering
valuable
functionality
Why test our micro-services?
“We test our micro-services so we can deploy new
features quickly and with confidence”
And with
aggressive
production
monitoring
Writing executable
specifications and
living
documentation
To a sufficient level
of confidence
Outside-in
testing
Pragmatic web service testing
And with
aggressive
production
monitoring
Writing executable
specifications and
living
documentation
To a sufficient level
of confidence
Outside-in
testing
Pragmatic web service testing
And with
aggressive
production
monitoring
Writing executable
specifications and
living
documentation
To a sufficient level
of confidence
Outside-in
testing
Pragmatic web service testing
And with
aggressive
production
monitoring
Writing executable
specifications and
living
documentation
To a sufficient level
of confidence
Outside-in
testing
Pragmatic web service testing
And with
aggressive
production
monitoring
Writing executable
specifications and
living
documentation
To a sufficient level
of confidence
Outside-in
testing
Pragmatic web service testing
And with
aggressive
production
monitoring
Writing executable
specifications and
living
documentation
To a sufficient level
of confidence
Outside-in
testing
Pragmatic web service testing
Outside-in development
To deliver
software that
matters
And a common
language to build
a shared
understanding
Using examples at
multiple levels
Collaborate to
discover
requirements and
identify uncertainty
The essence of BDD
To deliver
software that
matters
And a common
language to build
a shared
understanding
Using examples at
multiple levels
Collaborate to
discover
requirements and
identify uncertainty
The essence of BDD
To deliver
software that
matters
And a common
language to build
a shared
understanding
Using examples at
multiple levels
Collaborate to
discover
requirements and
identify uncertainty
The essence of BDD
To deliver
software that
matters
And a common
language to build
a shared
understanding
Using examples at
multiple levels
Collaborate to
discover
requirements and
identify uncertainty
The essence of BDD
To deliver
software that
matters
And a common
language to build
a shared
understanding
Using examples at
multiple levels
Collaborate to
discover
requirements and
identify uncertainty
The essence of BDD
The business owner
tells the business
analyst what he wants
1
2
The business
analyst writes a
requirements
document
3
The developer
translates the
requirements
into software
4 The tester
translates the
requirements
into test cases 5 The technical
writer translates
the software
into functional
and technical
documentation
A traditional development process
How does it work?
The business owner
tells the business
analyst what he wants
1
2
The business
analyst writes a
requirements
document
3
The developer
translates the
requirements
into software
4 The tester
translates the
requirements
into test cases 5 The technical
writer translates
the software
into functional
and technical
documentation
A traditional development process
How does it work?
The business owner
tells the business
analyst what he wants
1
2
The business
analyst writes a
requirements
document
3
The developer
translates the
requirements
into software
4 The tester
translates the
requirements
into test cases 5 The technical
writer translates
the software
into functional
and technical
documentation
A traditional development process
How does it work?
The business owner
tells the business
analyst what he wants
1
2
The business
analyst writes a
requirements
document
3
The developer
translates the
requirements
into software
4 The tester
translates the
requirements
into test cases 5 The technical
writer translates
the software
into functional
and technical
documentation
A traditional development process
How does it work?
The business owner
tells the business
analyst what he wants
1
2
The business
analyst writes a
requirements
document
3
The developer
translates the
requirements
into software
4 The tester
translates the
requirements
into test cases 5 The technical
writer translates
the software
into functional
and technical
documentation
A traditional development process
How does it work?
The business owner
tells the business
analyst what he wants
1
2
The business
analyst writes a
requirements
document
3
The developer
translates the
requirements
into software
4 The tester
translates the
requirements
into test cases 5 The technical
writer translates
the software
into functional
and technical
documentation
A traditional development process
How does it work?
The business owner
tells the business
analyst what he wants
1
2
The business
analyst writes a
requirements
document
3
The developer
translates the
requirements
into software
4 The tester
translates the
requirements
into test cases 5 The technical
writer translates
the software
into functional
and technical
documentation
A traditional development process
How does it work?
The business owner
tells the business
analyst what he wants
1
2
The business
analyst writes a
requirements
document
3
The developer
translates the
requirements
into software
4 The tester
translates the
requirements
into test cases 5 The technical
writer translates
the software
into functional
and technical
documentation
A traditional development process
How does it work?
The business owner
tells the business
analyst what he wants
1
2
The business
analyst writes a
requirements
document
3
The developer
translates the
requirements
into software
4 The tester
translates the
requirements
into test cases 5 The technical
writer translates
the software
into functional
and technical
documentation
A traditional development process
How does it work?
The business owner
tells the business
analyst what he wants
1
2
The business
analyst writes a
requirements
document
3
The developer
translates the
requirements
into software
4 The tester
translates the
requirements
into test cases 5 The technical
writer translates
the software
into functional
and technical
documentation
A traditional development process
How does it work?
The business owner
tells the business
analyst what he wants
1
2
The business
analyst writes a
requirements
document
3
The developer
translates the
requirements
into software
4 The tester
translates the
requirements
into test cases 5 The technical
writer translates
the software
into functional
and technical
documentation
A traditional development process
How does it work?
How does it work?
The business owner
and the business
analyst have a
conversation about
what he needs.
1
2
3
4 The tester uses
these scenarios
as the basis for
her tests
5
The automated tests provide
feedback on progress and help
document the application
The business analyst,
the developer and the
tester elaborate the
requirements together.
The scenarios guide the
developer and act as
automated tests
They define
requirements as
structured, English-
language format
"scenarios"
A BDD development process
How does it work?
The business owner
and the business
analyst have a
conversation about
what he needs.
1
2
3
4 The tester uses
these scenarios
as the basis for
her tests
5
The automated tests provide
feedback on progress and help
document the application
The business analyst,
the developer and the
tester elaborate the
requirements together.
The scenarios guide the
developer and act as
automated tests
They define
requirements as
structured, English-
language format
"scenarios"
A BDD development process
How does it work?
The business owner
and the business
analyst have a
conversation about
what he needs.
1
2
3
4 The tester uses
these scenarios
as the basis for
her tests
5
The automated tests provide
feedback on progress and help
document the application
The business analyst,
the developer and the
tester elaborate the
requirements together.
The scenarios guide the
developer and act as
automated tests
They define
requirements as
structured, English-
language format
"scenarios"
A BDD development process
How does it work?
The business owner
and the business
analyst have a
conversation about
what he needs.
1
2
3
4 The tester uses
these scenarios
as the basis for
her tests
5
The automated tests provide
feedback on progress and help
document the application
The business analyst,
the developer and the
tester elaborate the
requirements together.
The scenarios guide the
developer and act as
automated tests
They define
requirements as
structured, English-
language format
"scenarios"
A BDD development process
How does it work?
The business owner
and the business
analyst have a
conversation about
what he needs.
1
2
3
4 The tester uses
these scenarios
as the basis for
her tests
5
The automated tests provide
feedback on progress and help
document the application
The business analyst,
the developer and the
tester elaborate the
requirements together.
The scenarios guide the
developer and act as
automated tests
They define
requirements as
structured, English-
language format
"scenarios"
A BDD development process
How does it work?
The business owner
and the business
analyst have a
conversation about
what he needs.
1
2
3
4 The tester uses
these scenarios
as the basis for
her tests
5
The automated tests provide
feedback on progress and help
document the application
The business analyst,
the developer and the
tester elaborate the
requirements together.
The scenarios guide the
developer and act as
automated tests
They define
requirements as
structured, English-
language format
"scenarios"
A BDD development process
But what about micro-services?
The testing pyramid
Unit Tests
Integration Tests
End-to-end Tests
The testing pyramid
Unit Tests
Integration Tests
End-to-end Tests
A different testing pyramid
A different testing pyramid
Executable Business
Specifications
A different testing pyramid
Slow-running executable
technical specifications
Executable Business
Specifications
A different testing pyramid
Fast-running executable technical
specifications
Slow-running executable
technical specifications
Executable Business
Specifications
Outside-in development
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Executable
Business specs
Outside-in development
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Executable
Business specs
Scenario: Search movies by director

Given the catalog has the following movies:

| title | director | actors |

| Gladiator | Ridley Scott | Russel Crowe, Joaquin Phoenix |

| Letters from Iwo Jima | Clint Eastwood | Ken Watanabe |

| Gran Torino | Clint Eastwood | Clint Eastwood, Bee Vang |

When I search for movies directed by Clint Eastwood

Then I should be presented with the following movies:

| title | director | actors |

| Letters from Iwo Jima | Clint Eastwood | Ken Watanabe |

| Gran Torino | Clint Eastwood | Clint Eastwood, Bee Vang |

Outside-in development
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Slow-running
technical
specs
Outside-in development
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Slow-running
technical
specs
@ContextConfiguration(loader = SpringApplicationContextLoader.class, classes = MovieServiceApplication.class)

@WebAppConfiguration

@IntegrationTest("server.port:0")

class WhenFindingMoviesViaTheRestAPI extends Specification {



@Autowired

MovieRepository movieRepository;



@Value('${local.server.port}')

int port;



def "should list movies by director"() {

given:

movieCatalogContains([GLADIATOR, LETTERS_FROM_IWO_JIMA, GRAN_TORINO])

when:

List<Movie> movies = when().get("/movies/findByDirector/Clint Eastwood").as(List)

then:

movies.collect {movie -> movie.title} == ["Letters from Iwo Jima", "Gran Torino"]

}
Outside-in development
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Fast-
running
technical
specs
Outside-in development
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Fast-
running
technical
specs
def setup() {

repository = Mock(MovieRepository)

artistService = new ArtistService(movieRepository: repository)

}



def "should build actor details from films the artist has acted in and has directed"() {

given: "Clint Eastwood has directed some films"

repository.findByDirector("Clint Eastwood") >> [LETTERS_FROM_IWO_JIMA, GRAN_TORINO]

and: "Clint Eastwood has starred in some films"

repository.findByActors("Clint Eastwood") >> [THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO]

when:

def artistDetails = artistService.findArtistByName("Clint Eastwood")

then:

artistDetails.isPresent()

and:

artistDetails.get().name == "Clint Eastwood" &&

artistDetails.get().filmsActedIn == [THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO] &&

artistDetails.get().filmsDirected == [LETTERS_FROM_IWO_JIMA, GRAN_TORINO]

}
Spock
Outside-in development
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Fast-
running
technical
specs
Outside-in development
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Fast-
running
technical
specs
class MovieControllerSpecs extends Specification {



MovieRepository movieRepository = Mock()



def "should find by director regardless of case (#director -> #filteredDirector)"() {

given:

def controller = new MovieController(repository: movieRepository)

when:

controller.findByDirector(director)

then:

1*movieRepository.findByDirector(filteredDirector)

where:

director | filteredDirector

"Clint Eastwood" | "Clint Eastwood"

"Clint eastwood" | "Clint Eastwood"
Spock
Micro-service Contracts
Micro-service Contracts
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Shopping Cart
Service
Delivery Service
REST/HTTP
Micro-service Contracts
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Shopping
Cart Service
REST/HTTP
Delivery
Service
Micro-service Contracts
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Shopping
Cart Service
REST/HTTP
Consumer
Delivery
Service
Micro-service Contracts
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Shopping
Cart Service
REST/HTTP
Consumer
Producer
Delivery
Service
Micro-service Contracts
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Shopping
Cart Service
REST/HTTP
Consumer
Producer
Contract
Delivery
Service
Micro-service Contracts
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Shopping
Cart Service
REST/HTTP
Contract
Delivery
Service
Micro-service Contracts
Movie Catalog Service
Resource
Persistance Layer Gateway
Service Layer
Domain model
Repositories
Shopping
Cart Service
Delivery
Service
REST/HTTP
Contract
Mock
Shopping
Cart
Service
Micro-service Contracts
REST/HTTP
Movie Catalog
Service
Web app iPhone app Android app
Micro-service Contracts
REST/HTTP
Movie Catalog
Service
Web app iPhone app Android app
Producer
Micro-service Contracts
REST/HTTP
Movie Catalog
Service
Web app iPhone app Android app
Consumer
Producer
Micro-service Contracts
REST/HTTP
Movie Catalog
Service
Web app iPhone app Android app
Consumer
Producer
Consumer
Micro-service Contracts
REST/HTTP
Movie Catalog
Service
Web app iPhone app Android app
Consumer
Producer
Consumer Consumer
Micro-service Contracts
REST/HTTP
Movie Catalog
Service
Web app iPhone app Android app
Consumer
Producer
Consumer Consumer
Contract
Micro-service Contracts
REST/HTTP
Movie Catalog
Service
Web app iPhone app Android app
Consumer
Producer
Consumer Consumer
Contract
Micro-service Contracts
REST/HTTP
Movie Catalog
Service
Web app iPhone app Android app
Consumer
Producer
Consumer Consumer
Contract
Micro-service Contracts
REST/HTTP
Movie Catalog
Service
Web app iPhone app Android app
Consumer
Producer
Consumer Consumer
Contract
The Producer API is the sum
of the Consumer Contrats
Specialised ToolsPublished specificationsAutomated Acceptance
Criteria
Verifying the contracts
Specialised ToolsPublished specificationsAutomated Acceptance
Criteria
Verifying the contracts
Specialised ToolsPublished specificationsAutomated Acceptance
Criteria
Verifying the contracts
Specialised ToolsPublished specificationsAutomated Acceptance
Criteria
Verifying the contracts
Specialised ToolsPublished specificationsAutomated Acceptance
Criteria
Verifying the contracts
PactPactoMountebank
More specialised tools
PactPactoMountebank
More specialised tools
PactPactoMountebank
More specialised tools
PactPactoMountebank
More specialised tools
PactPactoMountebank
More specialised tools
PactPactoMountebank
More specialised tools
PactPactoMountebank
More specialised tools
Pact and Pacto

Consumer Driven Contract Testing
42
Consumer Movie Catalog
Service
Pact and Pacto

Consumer Driven Contract Testing
42
Consumer Movie Catalog
Service
Mock
Service
Pact help us create and
configure a mock service
Pact and Pacto

Consumer Driven Contract Testing
43
Consumer Movie Catalog
Service
Mock
Service
Pact and Pacto

Consumer Driven Contract Testing
43
Consumer Movie Catalog
Service
Mock
Service
We write specifications to
describe the expected
behaviour of the service
Pact and Pacto

Consumer Driven Contract Testing
44
Consumer Movie Catalog
Service
Mock
Service
Pact and Pacto

Consumer Driven Contract Testing
44
Consumer Movie Catalog
Service
Mock
Service
When we run these
specifications, the expected
behaviour is recorded in a
‘pact’ file
asdasdasda
asdasdasdas
asdasdasd
asdasdasda
asdasdasdasd
asdasdasdasd
asdasdasdas
Pact and Pacto

Consumer Driven Contract Testing
45
Consumer Movie Catalog
Service
Mock
Service
asdasdasda
asdasdasdas
asdasdasd
asdasdasda
asdasdasdasd
asdasdasdasd
asdasdasdas
Pact and Pacto

Consumer Driven Contract Testing
45
Consumer Movie Catalog
Service
Mock
Service
We can now use this ‘pact’ to
test(drive) the service
implementation
asdasdasda
asdasdasdas
asdasdasd
asdasdasda
asdasdasdasd
asdasdasdasd
asdasdasdas
Levels of confidence
From BDD to TDD
“How much automated testing?

As much as you need, but no more.”
Acceptance testing
Acceptance testing
Acceptance testing
Feature: Adding new movies

In order to sell more movies

As an online movie seller

I want to be able to add movies to the catalog



Scenario: Adding movies

Given the following movie has just come out

| title | director | actors |

| Jurassic World | Colin Trevorrow | Chris Pratt, Bryce Dallas Howard |

When I add this movie to the catalog

Then I should be able to find it in the catalog
Feature: Adding new movies

In order to sell more movies

As an online movie seller

I want to be able to add movies to the catalog



Scenario: Adding movies

Given the following movie has just come out

| title | director | actors |

| Jurassic World | Colin Trevorrow | Chris Pratt, Bryce Dallas Howard |

When I add this movie to the catalog

Then I should be able to find it in the catalog
Feature: Adding new movies

In order to sell more movies

As an online movie seller

I want to be able to add movies to the catalog



Scenario: Adding movies

Given the following movie has just come out

| title | director | actors |

| Jurassic World | Colin Trevorrow | Chris Pratt, Bryce Dallas Howard |

When I add this movie to the catalog

Then I should be able to find it in the catalog
@When("I add this movie to the catalog")

public void addMovieToCatalog() {

movieId = rest().given().contentType("application/json")

.content(newMovie)

.post("/movies")

.then().statusCode(200)

.and().extract().jsonPath().getString("id");

}
Feature: Adding new movies

In order to sell more movies

As an online movie seller

I want to be able to add movies to the catalog



Scenario: Adding movies

Given the following movie has just come out

| title | director | actors |

| Jurassic World | Colin Trevorrow | Chris Pratt, Bryce Dallas Howard |

When I add this movie to the catalog

Then I should be able to find it in the catalog
Feature: Adding new movies

In order to sell more movies

As an online movie seller

I want to be able to add movies to the catalog



Scenario: Adding movies

Given the following movie has just come out

| title | director | actors |

| Jurassic World | Colin Trevorrow | Chris Pratt, Bryce Dallas Howard |

When I add this movie to the catalog

Then I should be able to find it in the catalog
Feature: Adding new movies

In order to sell more movies

As an online movie seller

I want to be able to add movies to the catalog



Scenario: Adding movies

Given the following movie has just come out

| title | director | actors |

| Jurassic World | Colin Trevorrow | Chris Pratt, Bryce Dallas Howard |

When I add this movie to the catalog

Then I should be able to find it in the catalog
@Then("I should be able to find it in the catalog")

public void shouldBeAbleToFindMovieInCatalog() {

rest().given().contentType("application/json")

.get("/movies/{movieId}", movieId)

.then().statusCode(200)

.and().body("title", equalTo(newMovie.getTitle()))

.and().body("director", equalTo(newMovie.getDirector()));

}
Feature: Adding new movies

In order to sell more movies

As an online movie seller

I want to be able to add movies to the catalog



Scenario: Adding movies

Given the following movie has just come out

| title | director | actors |

| Jurassic World | Colin Trevorrow | Chris Pratt, Bryce Dallas Howard |

When I add this movie to the catalog

Then I should be able to find it in the catalog
@Then("I should be able to find it in the catalog")

public void shouldBeAbleToFindMovieInCatalog() {

rest().given().contentType("application/json")

.get("/movies/{movieId}", movieId)

.then().statusCode(200)

.and().body("title", equalTo(newMovie.getTitle()))

.and().body("director", equalTo(newMovie.getDirector()));

}
Rest Assured + Serenity
Feature: Adding new movies

In order to sell more movies

As an online movie seller

I want to be able to add movies to the catalog



Scenario: Adding movies

Given the following movie has just come out

| title | director | actors |

| Jurassic World | Colin Trevorrow | Chris Pratt, Bryce Dallas Howard |

When I add this movie to the catalog

Then I should be able to find it in the catalog
@Then("I should be able to find it in the catalog")

public void shouldBeAbleToFindMovieInCatalog() {

rest().given().contentType("application/json")

.get("/movies/{movieId}", movieId)

.then().statusCode(200)

.and().body("title", equalTo(newMovie.getTitle()))

.and().body("director", equalTo(newMovie.getDirector()));

}
Testing REST services with Rest-Assured
Testing REST services with Rest-Assured
get(“/movies/findByTitle/Gladiator")
.then().body("title", equalTo("Gladiator"));
Testing REST services with Rest-Assured
get(“/movies/findByTitle/Gladiator")
.then().body("title", equalTo("Gladiator"));
Testing REST services with Rest-Assured
when().get(“/movies/findByTitle/Gladiator”)
.then().body("nominations.category",
hasItems("Best Actor", "Special Effects"));
Testing REST services with Rest-Assured
when().get(“/movies/findByTitle/Gladiator”)
.then().body("nominations.category",
hasItems("Best Actor", "Special Effects"));
Testing REST services with Rest-Assured
given().contentType("application/json")

.content(newMovie)

.post("/movies")

.then().statusCode(200)

.and().extract().jsonPath().getString("id");
Testing REST services with Rest-Assured
given().contentType("application/json")

.content(newMovie)

.post("/movies")

.then().statusCode(200)

.and().extract().jsonPath().getString("id");
Posting data
Testing REST services with Rest-Assured
Movie matchingMovie
= get("/movies/findByTitle/Gladiator").as(Movie.class);
Testing REST services with Rest-Assured
Movie matchingMovie
= get("/movies/findByTitle/Gladiator").as(Movie.class);
Convert responses to Java objects
Testing REST services with Rest-Assured
given().param("title","Unknown").

when().get("/movies/search").

then().statusCode(404);
Testing REST services with Rest-Assured
given().param("title","Unknown").

when().get("/movies/search").

then().statusCode(404);
Check for errors
Resource-level testing
Resource-level testing
Spock
Resource-level testing
Spock
Resource-level testing
Spock
57
@ContextConfiguration(loader = SpringApplicationContextLoader.class,
classes = MovieServiceApplication.class)

@WebAppConfiguration

@IntegrationTest("server.port:0")

class WhenFindingMovies extends Specification {



@Autowired

MovieRepository movieRepository;



@Value('${local.server.port}')

int port;



def setup() {

movieRepository.deleteAll();

RestAssured.port = port;

}



def "should list all movies"() {

given:

movieCatalogContains([GLADIATOR, LETTERS_FROM_IWO_JIMA, GRAN_TORINO])

when:

def movies = when().get("/movies").as(List)

then:

movies.collect {movie -> movie.title} == ["Gladiator", 

"Letters from Iwo Jima", 

"Gran Torino"]

}
57
@ContextConfiguration(loader = SpringApplicationContextLoader.class,
classes = MovieServiceApplication.class)

@WebAppConfiguration

@IntegrationTest("server.port:0")

class WhenFindingMovies extends Specification {



@Autowired

MovieRepository movieRepository;



@Value('${local.server.port}')

int port;



def setup() {

movieRepository.deleteAll();

RestAssured.port = port;

}



def "should list all movies"() {

given:

movieCatalogContains([GLADIATOR, LETTERS_FROM_IWO_JIMA, GRAN_TORINO])

when:

def movies = when().get("/movies").as(List)

then:

movies.collect {movie -> movie.title} == ["Gladiator", 

"Letters from Iwo Jima", 

"Gran Torino"]

}
Spring Context
57
@ContextConfiguration(loader = SpringApplicationContextLoader.class,
classes = MovieServiceApplication.class)

@WebAppConfiguration

@IntegrationTest("server.port:0")

class WhenFindingMovies extends Specification {



@Autowired

MovieRepository movieRepository;



@Value('${local.server.port}')

int port;



def setup() {

movieRepository.deleteAll();

RestAssured.port = port;

}



def "should list all movies"() {

given:

movieCatalogContains([GLADIATOR, LETTERS_FROM_IWO_JIMA, GRAN_TORINO])

when:

def movies = when().get("/movies").as(List)

then:

movies.collect {movie -> movie.title} == ["Gladiator", 

"Letters from Iwo Jima", 

"Gran Torino"]

}
Spring Integration Tests
57
@ContextConfiguration(loader = SpringApplicationContextLoader.class,
classes = MovieServiceApplication.class)

@WebAppConfiguration

@IntegrationTest("server.port:0")

class WhenFindingMovies extends Specification {



@Autowired

MovieRepository movieRepository;



@Value('${local.server.port}')

int port;



def setup() {

movieRepository.deleteAll();

RestAssured.port = port;

}



def "should list all movies"() {

given:

movieCatalogContains([GLADIATOR, LETTERS_FROM_IWO_JIMA, GRAN_TORINO])

when:

def movies = when().get("/movies").as(List)

then:

movies.collect {movie -> movie.title} == ["Gladiator", 

"Letters from Iwo Jima", 

"Gran Torino"]

}
Rest Assured
57
@ContextConfiguration(loader = SpringApplicationContextLoader.class,
classes = MovieServiceApplication.class)

@WebAppConfiguration

@IntegrationTest("server.port:0")

class WhenFindingMovies extends Specification {



@Autowired

MovieRepository movieRepository;



@Value('${local.server.port}')

int port;



def setup() {

movieRepository.deleteAll();

RestAssured.port = port;

}



def "should list all movies"() {

given:

movieCatalogContains([GLADIATOR, LETTERS_FROM_IWO_JIMA, GRAN_TORINO])

when:

def movies = when().get("/movies").as(List)

then:

movies.collect {movie -> movie.title} == ["Gladiator", 

"Letters from Iwo Jima", 

"Gran Torino"]

}
Controller-level testing
Controller-level testing
Spock
Controller-level testing
Spock
@ContextConfiguration(loader = SpringApplicationContextLoader.class,

classes = MovieServiceApplication.class)

@WebAppConfiguration

@IntegrationTest

class WhenViewingActorDetailsViaTheController extends Specification {



@Autowired

ArtistController artistController;



def "should retrieve actor details for an artist"() {

given:

movieCatalogContains([GLADIATOR, LETTERS_FROM_IWO_JIMA,

THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO])

when:

Artist artist = artistController.findArtistDetails("Clint Eastwood")

then:

artist.name == "Clint Eastwood"

and:

artist.filmsActedIn.containsAll(THE_GOOD_THE_BAD_AND_THE_UGLY,
GRAN_TORINO)

and:

artist.filmsDirected.containsAll(LETTERS_FROM_IWO_JIMA, GRAN_TORINO)

}
@ContextConfiguration(loader = SpringApplicationContextLoader.class,

classes = MovieServiceApplication.class)

@WebAppConfiguration

@IntegrationTest

class WhenViewingActorDetailsViaTheController extends Specification {



@Autowired

ArtistController artistController;



def "should retrieve actor details for an artist"() {

given:

movieCatalogContains([GLADIATOR, LETTERS_FROM_IWO_JIMA,

THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO])

when:

Artist artist = artistController.findArtistDetails("Clint Eastwood")

then:

artist.name == "Clint Eastwood"

and:

artist.filmsActedIn.containsAll(THE_GOOD_THE_BAD_AND_THE_UGLY,
GRAN_TORINO)

and:

artist.filmsDirected.containsAll(LETTERS_FROM_IWO_JIMA, GRAN_TORINO)

}
Use a fully wired controller
@ContextConfiguration(loader = SpringApplicationContextLoader.class,

classes = MovieServiceApplication.class)

@WebAppConfiguration

@IntegrationTest

class WhenViewingActorDetailsViaTheController extends Specification {



@Autowired

ArtistController artistController;



def "should retrieve actor details for an artist"() {

given:

movieCatalogContains([GLADIATOR, LETTERS_FROM_IWO_JIMA,

THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO])

when:

Artist artist = artistController.findArtistDetails("Clint Eastwood")

then:

artist.name == "Clint Eastwood"

and:

artist.filmsActedIn.containsAll(THE_GOOD_THE_BAD_AND_THE_UGLY,
GRAN_TORINO)

and:

artist.filmsDirected.containsAll(LETTERS_FROM_IWO_JIMA, GRAN_TORINO)

}
Use domain objects rather than REST calls
@ContextConfiguration(loader = SpringApplicationContextLoader.class,

classes = MovieServiceApplication.class)

@WebAppConfiguration

@IntegrationTest

class WhenViewingActorDetailsViaTheController extends Specification {



@Autowired

ArtistController artistController;



def "should retrieve actor details for an artist"() {

given:

movieCatalogContains([GLADIATOR, LETTERS_FROM_IWO_JIMA,

THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO])

when:

Artist artist = artistController.findArtistDetails("Clint Eastwood")

then:

artist.name == "Clint Eastwood"

and:

artist.filmsActedIn.containsAll(THE_GOOD_THE_BAD_AND_THE_UGLY,
GRAN_TORINO)

and:

artist.filmsDirected.containsAll(LETTERS_FROM_IWO_JIMA, GRAN_TORINO)

}
Service or domain-level testing
Service or domain-level testing
Spock
MovieRepository repository

def artistService



def setup() {

repository = Mock(MovieRepository)

artistService = new ArtistService(movieRepository: repository)

}



def "should build actor details from films the artist has acted in and has directed"() {

given: "Clint Eastwood has directed some films"

repository.findByDirector("Clint Eastwood") >>
[LETTERS_FROM_IWO_JIMA, GRAN_TORINO]

and: "Clint Eastwood has starred in some films"

repository.findByActors("Clint Eastwood") >>
[THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO]

when:

def artistDetails = artistService.findArtistByName("Clint Eastwood")

then:

artistDetails.isPresent()

and:

artistDetails.get().name == "Clint Eastwood" &&

artistDetails.get().filmsActedIn == [THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO] &&

artistDetails.get().filmsDirected == [LETTERS_FROM_IWO_JIMA, GRAN_TORINO]

}
MovieRepository repository

def artistService



def setup() {

repository = Mock(MovieRepository)

artistService = new ArtistService(movieRepository: repository)

}



def "should build actor details from films the artist has acted in and has directed"() {

given: "Clint Eastwood has directed some films"

repository.findByDirector("Clint Eastwood") >>
[LETTERS_FROM_IWO_JIMA, GRAN_TORINO]

and: "Clint Eastwood has starred in some films"

repository.findByActors("Clint Eastwood") >>
[THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO]

when:

def artistDetails = artistService.findArtistByName("Clint Eastwood")

then:

artistDetails.isPresent()

and:

artistDetails.get().name == "Clint Eastwood" &&

artistDetails.get().filmsActedIn == [THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO] &&

artistDetails.get().filmsDirected == [LETTERS_FROM_IWO_JIMA, GRAN_TORINO]

}
Mocked repositories
MovieRepository repository

def artistService



def setup() {

repository = Mock(MovieRepository)

artistService = new ArtistService(movieRepository: repository)

}



def "should build actor details from films the artist has acted in and has directed"() {

given: "Clint Eastwood has directed some films"

repository.findByDirector("Clint Eastwood") >>
[LETTERS_FROM_IWO_JIMA, GRAN_TORINO]

and: "Clint Eastwood has starred in some films"

repository.findByActors("Clint Eastwood") >>
[THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO]

when:

def artistDetails = artistService.findArtistByName("Clint Eastwood")

then:

artistDetails.isPresent()

and:

artistDetails.get().name == "Clint Eastwood" &&

artistDetails.get().filmsActedIn == [THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO] &&

artistDetails.get().filmsDirected == [LETTERS_FROM_IWO_JIMA, GRAN_TORINO]

}
Call the service
MovieRepository repository

def artistService



def setup() {

repository = Mock(MovieRepository)

artistService = new ArtistService(movieRepository: repository)

}



def "should build actor details from films the artist has acted in and has directed"() {

given: "Clint Eastwood has directed some films"

repository.findByDirector("Clint Eastwood") >>
[LETTERS_FROM_IWO_JIMA, GRAN_TORINO]

and: "Clint Eastwood has starred in some films"

repository.findByActors("Clint Eastwood") >>
[THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO]

when:

def artistDetails = artistService.findArtistByName("Clint Eastwood")

then:

artistDetails.isPresent()

and:

artistDetails.get().name == "Clint Eastwood" &&

artistDetails.get().filmsActedIn == [THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO] &&

artistDetails.get().filmsDirected == [LETTERS_FROM_IWO_JIMA, GRAN_TORINO]

}
Check the outcomes
MovieRepository repository

def artistService



def setup() {

repository = Mock(MovieRepository)

artistService = new ArtistService(movieRepository: repository)

}



def "should build actor details from films the artist has acted in and has directed"() {

given: "Clint Eastwood has directed some films"

repository.findByDirector("Clint Eastwood") >>
[LETTERS_FROM_IWO_JIMA, GRAN_TORINO]

and: "Clint Eastwood has starred in some films"

repository.findByActors("Clint Eastwood") >>
[THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO]

when:

def artistDetails = artistService.findArtistByName("Clint Eastwood")

then:

artistDetails.isPresent()

and:

artistDetails.get().name == "Clint Eastwood" &&

artistDetails.get().filmsActedIn == [THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO] &&

artistDetails.get().filmsDirected == [LETTERS_FROM_IWO_JIMA, GRAN_TORINO]

}
Living Documentation
Living Documentation
Living Functional Documentation
with Serenity and Cucumber
65
Scenario: Adding movies

Given the following movie has just come out

| title | director | actors |

| Jurassic World | Colin Trevorrow | Chris Pratt, Bryce Dallas Howard |

When I add this movie to the catalog

Then I should be able to find it in the catalog
Executable Specifications
Automated tests Living documentation
66
66
Context
66
Context
Narrative
67
67
Technical details
Living API Documentation 

with Swagger
Springfox
69
YAML Specifications
Documentation
website
Client libraries Test stubs
70
@RequestMapping(method = GET)

@ApiOperation("List all the movies in the catalog")

public List<Movie> findAll() {

return repository.findAll();

}



@RequestMapping(method = POST)

@ApiOperation(value = "Add a new movie to the catalog", httpMethod = "POST")

public Movie add(@RequestBody Movie newMovie) {

return repository.save(newMovie);

}



@RequestMapping(value = "/{id}", method = DELETE)

@ApiOperation(value = "Removing a movie from the catalog", httpMethod = "DELETE")

public void delete(@PathVariable String id) {

repository.delete(id);

}

Springfox
Some annotations…
Swagger and Spring Boot
70
@RequestMapping(method = GET)

@ApiOperation("List all the movies in the catalog")

public List<Movie> findAll() {

return repository.findAll();

}



@RequestMapping(method = POST)

@ApiOperation(value = "Add a new movie to the catalog", httpMethod = "POST")

public Movie add(@RequestBody Movie newMovie) {

return repository.save(newMovie);

}



@RequestMapping(value = "/{id}", method = DELETE)

@ApiOperation(value = "Removing a movie from the catalog", httpMethod = "DELETE")

public void delete(@PathVariable String id) {

repository.delete(id);

}

Springfox
Some annotations…
Swagger and Spring Boot
70
@RequestMapping(method = GET)

@ApiOperation("List all the movies in the catalog")

public List<Movie> findAll() {

return repository.findAll();

}



@RequestMapping(method = POST)

@ApiOperation(value = "Add a new movie to the catalog", httpMethod = "POST")

public Movie add(@RequestBody Movie newMovie) {

return repository.save(newMovie);

}



@RequestMapping(value = "/{id}", method = DELETE)

@ApiOperation(value = "Removing a movie from the catalog", httpMethod = "DELETE")

public void delete(@PathVariable String id) {

repository.delete(id);

}

Springfox
Some annotations…
Swagger and Spring Boot
70
@RequestMapping(method = GET)

@ApiOperation("List all the movies in the catalog")

public List<Movie> findAll() {

return repository.findAll();

}



@RequestMapping(method = POST)

@ApiOperation(value = "Add a new movie to the catalog", httpMethod = "POST")

public Movie add(@RequestBody Movie newMovie) {

return repository.save(newMovie);

}



@RequestMapping(value = "/{id}", method = DELETE)

@ApiOperation(value = "Removing a movie from the catalog", httpMethod = "DELETE")

public void delete(@PathVariable String id) {

repository.delete(id);

}

Springfox
Some annotations…
Swagger and Spring Boot
71
Springfox
@EnableAutoConfiguration

@EnableSwagger2

public class MovieServiceApplication {



public static void main(String[] args) {

SpringApplication.run(MovieServiceApplication.class, args);

}



@Bean

public Docket moviesApi() {

return new Docket(DocumentationType.SWAGGER_2)

.select()

.apis(RequestHandlerSelectors.any())

.paths(PathSelectors.any())

.build()

.pathMapping("/")

.directModelSubstitute(LocalDate.class, String.class)

.genericModelSubstitutes(ResponseEntity.class);

}

} Some configuration…
Swagger and Spring Boot
72
Springfox
Documentation

bundled with your
web services
Swagger and Spring Boot
Production monitoring
Automated MonitoringFast provisioningA fast deployment pipeline
So you want to micro-service?
Automated health checksReal operationsSmoke tests in production
Simple checks may not be enough
An example with Spring Actuator
@Component

public class CatalogHealth implements HealthIndicator {



@Autowired

MovieRepository movieRepository;



@Override

public Health health() {

return (isCatalogStocked()) ? 

Health.status(new Status("UP", "Movie count: " + movieRepository.count())).build() 

: Health.down().build();

}



private boolean isCatalogStocked() {

return (movieRepository.count() > 0);

}

}
An example with Spring Actuator
@Component

public class CatalogHealth implements HealthIndicator {



@Autowired

MovieRepository movieRepository;



@Override

public Health health() {

return (isCatalogStocked()) ? 

Health.status(new Status("UP", "Movie count: " + movieRepository.count())).build() 

: Health.down().build();

}



private boolean isCatalogStocked() {

return (movieRepository.count() > 0);

}

}
A Spring Actuator Health Check
An example with Spring Actuator
@Component

public class CatalogHealth implements HealthIndicator {



@Autowired

MovieRepository movieRepository;



@Override

public Health health() {

return (isCatalogStocked()) ? 

Health.status(new Status("UP", "Movie count: " + movieRepository.count())).build() 

: Health.down().build();

}



private boolean isCatalogStocked() {

return (movieRepository.count() > 0);

}

}
A Spring Actuator Health Check
Custom logic to decide if the app is working
An example with Spring Actuator
@Component

public class MovieTransactionHealth implements HealthIndicator {



@Autowired

MovieController movieController;



@Override

public Health health() {

return Health.status(transactionStatus()).build();

}



private Status transactionStatus() {

try {

Movie movie = new Movie("TEST title", "TEST description", "TEST director",
ImmutableList.of("TEST actor"));

Movie reloadedMovie = movieController.add(movie);

movieController.delete(reloadedMovie.getId());

return Status.UP;

} catch (Throwable e) {

return new Status("DOWN", e.toString());

}

}

}
An example with Spring Actuator
@Component

public class MovieTransactionHealth implements HealthIndicator {



@Autowired

MovieController movieController;



@Override

public Health health() {

return Health.status(transactionStatus()).build();

}



private Status transactionStatus() {

try {

Movie movie = new Movie("TEST title", "TEST description", "TEST director",
ImmutableList.of("TEST actor"));

Movie reloadedMovie = movieController.add(movie);

movieController.delete(reloadedMovie.getId());

return Status.UP;

} catch (Throwable e) {

return new Status("DOWN", e.toString());

}

}

}
More complex custom logic
An example with Spring Actuator
@Component

public class MovieTransactionHealth implements HealthIndicator {



@Autowired

MovieController movieController;



@Override

public Health health() {

return Health.status(transactionStatus()).build();

}



private Status transactionStatus() {…}

}
@Component

public class CatalogHealth implements HealthIndicator {



@Autowired

MovieRepository movieRepository;



@Override

public Health health() {

return (isCatalogStocked()) ? 

Health.status(new Status("UP", "Movie count: " + 

movieRepository.count())).build() 

: Health.down().build();

}



private boolean isCatalogStocked() {…}

}
Try all this out at home!
Install Gradle
Install MongoDB
Clone the repowakaleo/movie-service
Questions?
John Ferguson Smart
john.smart@wakaleo.com
wakaleo
http://www.wakaleo.com

BDD-Driven Microservices

  • 1.
    Tools, techniques andreflections BDD-Driven Microservices in Java
  • 2.
    John Ferguson Smart Introductions “I help teamsof smart people 
 learn to work together more efficiently, 
 to deliver better software faster”
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
    Microservices 101 Movie Catalog Service Authentication Service ShoppingCart Service Delivery Service Payment Service REST/HTTP
  • 10.
    Microservices 101 Movie Catalog Service Authentication Service ShoppingCart Service Delivery Service Payment Service Event Bus
  • 11.
  • 12.
  • 13.
    Microservices 101 Movie CatalogService Resource Service Layer Domain model Repositories
  • 14.
    Microservices 101 Movie CatalogService Resource Persistance Layer Service Layer Domain model Repositories
  • 15.
    Microservices 101 Movie CatalogService Resource Persistance Layer Gateway Service Layer Domain model Repositories
  • 16.
  • 17.
  • 18.
    The testing pyramid UnitTests Integration Tests
  • 19.
    The testing pyramid UnitTests Integration Tests End-to-end Tests
  • 20.
    The testing pyramid UnitTests Integration Tests End-to-end Tests
  • 21.
    The testing pyramid UnitTests Integration Tests End-to-end Tests
  • 22.
    The testing pyramid UnitTests Integration Tests End-to-end Tests
  • 23.
    The testing pyramid MovieCatalog Service Resource Persistance Layer Gateway Service Layer Domain model Repositories Unit Tests
  • 24.
    The testing pyramid MovieCatalog Service Resource Persistance Layer Gateway Service Layer Domain model Repositories Unit Tests
  • 25.
    The testing pyramid MovieCatalog Service Resource Persistance Layer Gateway Service Layer Domain model Repositories Unit Tests
  • 26.
    The testing pyramid MovieCatalog Service Resource Persistance Layer Gateway Service Layer Domain model Repositories Unit Tests
  • 27.
    The testing pyramid MovieCatalog Service Resource Persistance Layer Gateway Service Layer Domain model Repositories Unit Tests
  • 28.
    The testing pyramid MovieCatalog Service Resource Persistance Layer Gateway Service Layer Domain model Repositories Unit Tests
  • 29.
    The testing pyramid MovieCatalog Service Resource Persistance Layer Gateway Service Layer Domain model Repositories Unit Tests
  • 30.
    The testing pyramid MovieCatalog Service Resource Persistance Layer Gateway Service Layer Domain model Repositories Unit Tests
  • 31.
    The testing pyramid MovieCatalog Service Resource Persistance Layer Gateway Service Layer Domain model Repositories Unit Tests
  • 32.
    The testing pyramid MovieCatalog Service Resource Persistance Layer Gateway Service Layer Domain model Repositories Integration Tests
  • 33.
    The testing pyramid MovieCatalog Service Resource Persistance Layer Gateway Service Layer Domain model Repositories Integration Tests
  • 34.
    The testing pyramid MovieCatalog Service Resource Persistance Layer Gateway Service Layer Domain model Repositories Integration Tests
  • 35.
    The testing pyramid MovieCatalog Service Resource Persistance Layer Gateway Service Layer Domain model Repositories Integration Tests
  • 36.
    The testing pyramid MovieCatalog Service Resource Persistance Layer Gateway Service Layer Domain model Repositories Integration Tests
  • 37.
    The testing pyramidEnd-to-End Tests Movie Catalog Service Authentication Service Shopping Cart Service Delivery Service Payment Service Event Bus
  • 38.
    The testing pyramidEnd-to-End Tests Movie Catalog Service Authentication Service Shopping Cart Service Delivery Service Payment Service Event Bus
  • 39.
    The testing pyramidEnd-to-End Tests Movie Catalog Service Authentication Service Shopping Cart Service Delivery Service Payment Service Event Bus
  • 40.
    The testing pyramidEnd-to-End Tests Movie Catalog Service Authentication Service Shopping Cart Service Delivery Service Payment Service Event Bus
  • 41.
    The testing pyramidEnd-to-End Tests Movie Catalog Service Authentication Service Shopping Cart Service Delivery Service Payment Service Event Bus
  • 42.
    The testing pyramidEnd-to-End Tests Movie Catalog Service Authentication Service Shopping Cart Service Delivery Service Payment Service Event Bus
  • 43.
    The testing pyramidEnd-to-End Tests Movie Catalog Service Authentication Service Shopping Cart Service Delivery Service Payment Service Event Bus
  • 44.
    The testing pyramid UnitTests Integration Tests End-to-end Tests
  • 45.
    The testing pyramid UnitTests Integration Tests End-to-end Tests
  • 46.
    The testing pyramid UnitTests Integration Tests End-to-end Tests
  • 47.
    The testing pyramid UnitTests Integration Tests End-to-end Tests
  • 48.
    The testing pyramid UnitTests Integration Tests End-to-end Tests
  • 49.
    The testing pyramid UnitTests Integration Tests End-to-end Tests
  • 50.
    The testing pyramid UnitTests Integration Tests End-to-end Tests
  • 51.
    The testing pyramid UnitTests Integration Tests End-to-end Tests
  • 52.
    The testing pyramid UnitTests Integration Tests End-to-end Tests
  • 53.
    The testing pyramid UnitTests Integration Tests End-to-end Tests
  • 54.
    The testing pyramid UnitTests Integration Tests End-to-end Tests
  • 55.
    To document how tointeract with the microservice To document what the microservice does To ensure the service work correctly To ensure we are delivering valuable functionality Why test our micro-services?
  • 56.
    To document how tointeract with the microservice To document what the microservice does To ensure the service work correctly To ensure we are delivering valuable functionality Why test our micro-services?
  • 57.
    To document how tointeract with the microservice To document what the microservice does To ensure the service work correctly To ensure we are delivering valuable functionality Why test our micro-services?
  • 58.
    To document how tointeract with the microservice To document what the microservice does To ensure the service work correctly To ensure we are delivering valuable functionality Why test our micro-services?
  • 59.
    To document how tointeract with the microservice To document what the microservice does To ensure the service work correctly To ensure we are delivering valuable functionality Why test our micro-services?
  • 60.
    To document how tointeract with the microservice To document what the microservice does To ensure the service work correctly To ensure we are delivering valuable functionality Why test our micro-services?
  • 61.
    “We test ourmicro-services so we can deploy new features quickly and with confidence”
  • 62.
    And with aggressive production monitoring Writing executable specificationsand living documentation To a sufficient level of confidence Outside-in testing Pragmatic web service testing
  • 63.
    And with aggressive production monitoring Writing executable specificationsand living documentation To a sufficient level of confidence Outside-in testing Pragmatic web service testing
  • 64.
    And with aggressive production monitoring Writing executable specificationsand living documentation To a sufficient level of confidence Outside-in testing Pragmatic web service testing
  • 65.
    And with aggressive production monitoring Writing executable specificationsand living documentation To a sufficient level of confidence Outside-in testing Pragmatic web service testing
  • 66.
    And with aggressive production monitoring Writing executable specificationsand living documentation To a sufficient level of confidence Outside-in testing Pragmatic web service testing
  • 67.
    And with aggressive production monitoring Writing executable specificationsand living documentation To a sufficient level of confidence Outside-in testing Pragmatic web service testing
  • 68.
  • 69.
    To deliver software that matters Anda common language to build a shared understanding Using examples at multiple levels Collaborate to discover requirements and identify uncertainty The essence of BDD
  • 70.
    To deliver software that matters Anda common language to build a shared understanding Using examples at multiple levels Collaborate to discover requirements and identify uncertainty The essence of BDD
  • 71.
    To deliver software that matters Anda common language to build a shared understanding Using examples at multiple levels Collaborate to discover requirements and identify uncertainty The essence of BDD
  • 72.
    To deliver software that matters Anda common language to build a shared understanding Using examples at multiple levels Collaborate to discover requirements and identify uncertainty The essence of BDD
  • 73.
    To deliver software that matters Anda common language to build a shared understanding Using examples at multiple levels Collaborate to discover requirements and identify uncertainty The essence of BDD
  • 74.
    The business owner tellsthe business analyst what he wants 1 2 The business analyst writes a requirements document 3 The developer translates the requirements into software 4 The tester translates the requirements into test cases 5 The technical writer translates the software into functional and technical documentation A traditional development process How does it work?
  • 75.
    The business owner tellsthe business analyst what he wants 1 2 The business analyst writes a requirements document 3 The developer translates the requirements into software 4 The tester translates the requirements into test cases 5 The technical writer translates the software into functional and technical documentation A traditional development process How does it work?
  • 76.
    The business owner tellsthe business analyst what he wants 1 2 The business analyst writes a requirements document 3 The developer translates the requirements into software 4 The tester translates the requirements into test cases 5 The technical writer translates the software into functional and technical documentation A traditional development process How does it work?
  • 77.
    The business owner tellsthe business analyst what he wants 1 2 The business analyst writes a requirements document 3 The developer translates the requirements into software 4 The tester translates the requirements into test cases 5 The technical writer translates the software into functional and technical documentation A traditional development process How does it work?
  • 78.
    The business owner tellsthe business analyst what he wants 1 2 The business analyst writes a requirements document 3 The developer translates the requirements into software 4 The tester translates the requirements into test cases 5 The technical writer translates the software into functional and technical documentation A traditional development process How does it work?
  • 79.
    The business owner tellsthe business analyst what he wants 1 2 The business analyst writes a requirements document 3 The developer translates the requirements into software 4 The tester translates the requirements into test cases 5 The technical writer translates the software into functional and technical documentation A traditional development process How does it work?
  • 80.
    The business owner tellsthe business analyst what he wants 1 2 The business analyst writes a requirements document 3 The developer translates the requirements into software 4 The tester translates the requirements into test cases 5 The technical writer translates the software into functional and technical documentation A traditional development process How does it work?
  • 81.
    The business owner tellsthe business analyst what he wants 1 2 The business analyst writes a requirements document 3 The developer translates the requirements into software 4 The tester translates the requirements into test cases 5 The technical writer translates the software into functional and technical documentation A traditional development process How does it work?
  • 82.
    The business owner tellsthe business analyst what he wants 1 2 The business analyst writes a requirements document 3 The developer translates the requirements into software 4 The tester translates the requirements into test cases 5 The technical writer translates the software into functional and technical documentation A traditional development process How does it work?
  • 83.
    The business owner tellsthe business analyst what he wants 1 2 The business analyst writes a requirements document 3 The developer translates the requirements into software 4 The tester translates the requirements into test cases 5 The technical writer translates the software into functional and technical documentation A traditional development process How does it work?
  • 84.
    The business owner tellsthe business analyst what he wants 1 2 The business analyst writes a requirements document 3 The developer translates the requirements into software 4 The tester translates the requirements into test cases 5 The technical writer translates the software into functional and technical documentation A traditional development process How does it work?
  • 85.
    How does itwork? The business owner and the business analyst have a conversation about what he needs. 1 2 3 4 The tester uses these scenarios as the basis for her tests 5 The automated tests provide feedback on progress and help document the application The business analyst, the developer and the tester elaborate the requirements together. The scenarios guide the developer and act as automated tests They define requirements as structured, English- language format "scenarios" A BDD development process
  • 86.
    How does itwork? The business owner and the business analyst have a conversation about what he needs. 1 2 3 4 The tester uses these scenarios as the basis for her tests 5 The automated tests provide feedback on progress and help document the application The business analyst, the developer and the tester elaborate the requirements together. The scenarios guide the developer and act as automated tests They define requirements as structured, English- language format "scenarios" A BDD development process
  • 87.
    How does itwork? The business owner and the business analyst have a conversation about what he needs. 1 2 3 4 The tester uses these scenarios as the basis for her tests 5 The automated tests provide feedback on progress and help document the application The business analyst, the developer and the tester elaborate the requirements together. The scenarios guide the developer and act as automated tests They define requirements as structured, English- language format "scenarios" A BDD development process
  • 88.
    How does itwork? The business owner and the business analyst have a conversation about what he needs. 1 2 3 4 The tester uses these scenarios as the basis for her tests 5 The automated tests provide feedback on progress and help document the application The business analyst, the developer and the tester elaborate the requirements together. The scenarios guide the developer and act as automated tests They define requirements as structured, English- language format "scenarios" A BDD development process
  • 89.
    How does itwork? The business owner and the business analyst have a conversation about what he needs. 1 2 3 4 The tester uses these scenarios as the basis for her tests 5 The automated tests provide feedback on progress and help document the application The business analyst, the developer and the tester elaborate the requirements together. The scenarios guide the developer and act as automated tests They define requirements as structured, English- language format "scenarios" A BDD development process
  • 90.
    How does itwork? The business owner and the business analyst have a conversation about what he needs. 1 2 3 4 The tester uses these scenarios as the basis for her tests 5 The automated tests provide feedback on progress and help document the application The business analyst, the developer and the tester elaborate the requirements together. The scenarios guide the developer and act as automated tests They define requirements as structured, English- language format "scenarios" A BDD development process
  • 91.
    But what aboutmicro-services?
  • 92.
    The testing pyramid UnitTests Integration Tests End-to-end Tests
  • 93.
    The testing pyramid UnitTests Integration Tests End-to-end Tests
  • 94.
  • 95.
    A different testingpyramid Executable Business Specifications
  • 96.
    A different testingpyramid Slow-running executable technical specifications Executable Business Specifications
  • 97.
    A different testingpyramid Fast-running executable technical specifications Slow-running executable technical specifications Executable Business Specifications
  • 98.
    Outside-in development Movie CatalogService Resource Persistance Layer Gateway Service Layer Domain model Repositories Executable Business specs
  • 99.
    Outside-in development Movie CatalogService Resource Persistance Layer Gateway Service Layer Domain model Repositories Executable Business specs Scenario: Search movies by director
 Given the catalog has the following movies:
 | title | director | actors |
 | Gladiator | Ridley Scott | Russel Crowe, Joaquin Phoenix |
 | Letters from Iwo Jima | Clint Eastwood | Ken Watanabe |
 | Gran Torino | Clint Eastwood | Clint Eastwood, Bee Vang |
 When I search for movies directed by Clint Eastwood
 Then I should be presented with the following movies:
 | title | director | actors |
 | Letters from Iwo Jima | Clint Eastwood | Ken Watanabe |
 | Gran Torino | Clint Eastwood | Clint Eastwood, Bee Vang |

  • 100.
    Outside-in development Movie CatalogService Resource Persistance Layer Gateway Service Layer Domain model Repositories Slow-running technical specs
  • 101.
    Outside-in development Movie CatalogService Resource Persistance Layer Gateway Service Layer Domain model Repositories Slow-running technical specs @ContextConfiguration(loader = SpringApplicationContextLoader.class, classes = MovieServiceApplication.class)
 @WebAppConfiguration
 @IntegrationTest("server.port:0")
 class WhenFindingMoviesViaTheRestAPI extends Specification {
 
 @Autowired
 MovieRepository movieRepository;
 
 @Value('${local.server.port}')
 int port;
 
 def "should list movies by director"() {
 given:
 movieCatalogContains([GLADIATOR, LETTERS_FROM_IWO_JIMA, GRAN_TORINO])
 when:
 List<Movie> movies = when().get("/movies/findByDirector/Clint Eastwood").as(List)
 then:
 movies.collect {movie -> movie.title} == ["Letters from Iwo Jima", "Gran Torino"]
 }
  • 102.
    Outside-in development Movie CatalogService Resource Persistance Layer Gateway Service Layer Domain model Repositories Fast- running technical specs
  • 103.
    Outside-in development Movie CatalogService Resource Persistance Layer Gateway Service Layer Domain model Repositories Fast- running technical specs def setup() {
 repository = Mock(MovieRepository)
 artistService = new ArtistService(movieRepository: repository)
 }
 
 def "should build actor details from films the artist has acted in and has directed"() {
 given: "Clint Eastwood has directed some films"
 repository.findByDirector("Clint Eastwood") >> [LETTERS_FROM_IWO_JIMA, GRAN_TORINO]
 and: "Clint Eastwood has starred in some films"
 repository.findByActors("Clint Eastwood") >> [THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO]
 when:
 def artistDetails = artistService.findArtistByName("Clint Eastwood")
 then:
 artistDetails.isPresent()
 and:
 artistDetails.get().name == "Clint Eastwood" &&
 artistDetails.get().filmsActedIn == [THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO] &&
 artistDetails.get().filmsDirected == [LETTERS_FROM_IWO_JIMA, GRAN_TORINO]
 } Spock
  • 104.
    Outside-in development Movie CatalogService Resource Persistance Layer Gateway Service Layer Domain model Repositories Fast- running technical specs
  • 105.
    Outside-in development Movie CatalogService Resource Persistance Layer Gateway Service Layer Domain model Repositories Fast- running technical specs class MovieControllerSpecs extends Specification {
 
 MovieRepository movieRepository = Mock()
 
 def "should find by director regardless of case (#director -> #filteredDirector)"() {
 given:
 def controller = new MovieController(repository: movieRepository)
 when:
 controller.findByDirector(director)
 then:
 1*movieRepository.findByDirector(filteredDirector)
 where:
 director | filteredDirector
 "Clint Eastwood" | "Clint Eastwood"
 "Clint eastwood" | "Clint Eastwood" Spock
  • 106.
  • 107.
    Micro-service Contracts Movie CatalogService Resource Persistance Layer Gateway Service Layer Domain model Repositories Shopping Cart Service Delivery Service REST/HTTP
  • 108.
    Micro-service Contracts Movie CatalogService Resource Persistance Layer Gateway Service Layer Domain model Repositories Shopping Cart Service REST/HTTP Delivery Service
  • 109.
    Micro-service Contracts Movie CatalogService Resource Persistance Layer Gateway Service Layer Domain model Repositories Shopping Cart Service REST/HTTP Consumer Delivery Service
  • 110.
    Micro-service Contracts Movie CatalogService Resource Persistance Layer Gateway Service Layer Domain model Repositories Shopping Cart Service REST/HTTP Consumer Producer Delivery Service
  • 111.
    Micro-service Contracts Movie CatalogService Resource Persistance Layer Gateway Service Layer Domain model Repositories Shopping Cart Service REST/HTTP Consumer Producer Contract Delivery Service
  • 112.
    Micro-service Contracts Movie CatalogService Resource Persistance Layer Gateway Service Layer Domain model Repositories Shopping Cart Service REST/HTTP Contract Delivery Service
  • 113.
    Micro-service Contracts Movie CatalogService Resource Persistance Layer Gateway Service Layer Domain model Repositories Shopping Cart Service Delivery Service REST/HTTP Contract Mock Shopping Cart Service
  • 114.
  • 115.
  • 116.
    Micro-service Contracts REST/HTTP Movie Catalog Service Webapp iPhone app Android app Consumer Producer
  • 117.
    Micro-service Contracts REST/HTTP Movie Catalog Service Webapp iPhone app Android app Consumer Producer Consumer
  • 118.
    Micro-service Contracts REST/HTTP Movie Catalog Service Webapp iPhone app Android app Consumer Producer Consumer Consumer
  • 119.
    Micro-service Contracts REST/HTTP Movie Catalog Service Webapp iPhone app Android app Consumer Producer Consumer Consumer Contract
  • 120.
    Micro-service Contracts REST/HTTP Movie Catalog Service Webapp iPhone app Android app Consumer Producer Consumer Consumer Contract
  • 121.
    Micro-service Contracts REST/HTTP Movie Catalog Service Webapp iPhone app Android app Consumer Producer Consumer Consumer Contract
  • 122.
    Micro-service Contracts REST/HTTP Movie Catalog Service Webapp iPhone app Android app Consumer Producer Consumer Consumer Contract The Producer API is the sum of the Consumer Contrats
  • 123.
    Specialised ToolsPublished specificationsAutomatedAcceptance Criteria Verifying the contracts
  • 124.
    Specialised ToolsPublished specificationsAutomatedAcceptance Criteria Verifying the contracts
  • 125.
    Specialised ToolsPublished specificationsAutomatedAcceptance Criteria Verifying the contracts
  • 126.
    Specialised ToolsPublished specificationsAutomatedAcceptance Criteria Verifying the contracts
  • 127.
    Specialised ToolsPublished specificationsAutomatedAcceptance Criteria Verifying the contracts
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
    Pact and Pacto
 ConsumerDriven Contract Testing 42 Consumer Movie Catalog Service
  • 136.
    Pact and Pacto
 ConsumerDriven Contract Testing 42 Consumer Movie Catalog Service Mock Service Pact help us create and configure a mock service
  • 137.
    Pact and Pacto
 ConsumerDriven Contract Testing 43 Consumer Movie Catalog Service Mock Service
  • 138.
    Pact and Pacto
 ConsumerDriven Contract Testing 43 Consumer Movie Catalog Service Mock Service We write specifications to describe the expected behaviour of the service
  • 139.
    Pact and Pacto
 ConsumerDriven Contract Testing 44 Consumer Movie Catalog Service Mock Service
  • 140.
    Pact and Pacto
 ConsumerDriven Contract Testing 44 Consumer Movie Catalog Service Mock Service When we run these specifications, the expected behaviour is recorded in a ‘pact’ file asdasdasda asdasdasdas asdasdasd asdasdasda asdasdasdasd asdasdasdasd asdasdasdas
  • 141.
    Pact and Pacto
 ConsumerDriven Contract Testing 45 Consumer Movie Catalog Service Mock Service asdasdasda asdasdasdas asdasdasd asdasdasda asdasdasdasd asdasdasdasd asdasdasdas
  • 142.
    Pact and Pacto
 ConsumerDriven Contract Testing 45 Consumer Movie Catalog Service Mock Service We can now use this ‘pact’ to test(drive) the service implementation asdasdasda asdasdasdas asdasdasd asdasdasda asdasdasdasd asdasdasdasd asdasdasdas
  • 143.
  • 144.
    From BDD toTDD “How much automated testing?
 As much as you need, but no more.”
  • 145.
  • 146.
  • 147.
  • 148.
    Feature: Adding newmovies
 In order to sell more movies
 As an online movie seller
 I want to be able to add movies to the catalog
 
 Scenario: Adding movies
 Given the following movie has just come out
 | title | director | actors |
 | Jurassic World | Colin Trevorrow | Chris Pratt, Bryce Dallas Howard |
 When I add this movie to the catalog
 Then I should be able to find it in the catalog
  • 149.
    Feature: Adding newmovies
 In order to sell more movies
 As an online movie seller
 I want to be able to add movies to the catalog
 
 Scenario: Adding movies
 Given the following movie has just come out
 | title | director | actors |
 | Jurassic World | Colin Trevorrow | Chris Pratt, Bryce Dallas Howard |
 When I add this movie to the catalog
 Then I should be able to find it in the catalog
  • 150.
    Feature: Adding newmovies
 In order to sell more movies
 As an online movie seller
 I want to be able to add movies to the catalog
 
 Scenario: Adding movies
 Given the following movie has just come out
 | title | director | actors |
 | Jurassic World | Colin Trevorrow | Chris Pratt, Bryce Dallas Howard |
 When I add this movie to the catalog
 Then I should be able to find it in the catalog @When("I add this movie to the catalog")
 public void addMovieToCatalog() {
 movieId = rest().given().contentType("application/json")
 .content(newMovie)
 .post("/movies")
 .then().statusCode(200)
 .and().extract().jsonPath().getString("id");
 }
  • 151.
    Feature: Adding newmovies
 In order to sell more movies
 As an online movie seller
 I want to be able to add movies to the catalog
 
 Scenario: Adding movies
 Given the following movie has just come out
 | title | director | actors |
 | Jurassic World | Colin Trevorrow | Chris Pratt, Bryce Dallas Howard |
 When I add this movie to the catalog
 Then I should be able to find it in the catalog
  • 152.
    Feature: Adding newmovies
 In order to sell more movies
 As an online movie seller
 I want to be able to add movies to the catalog
 
 Scenario: Adding movies
 Given the following movie has just come out
 | title | director | actors |
 | Jurassic World | Colin Trevorrow | Chris Pratt, Bryce Dallas Howard |
 When I add this movie to the catalog
 Then I should be able to find it in the catalog
  • 153.
    Feature: Adding newmovies
 In order to sell more movies
 As an online movie seller
 I want to be able to add movies to the catalog
 
 Scenario: Adding movies
 Given the following movie has just come out
 | title | director | actors |
 | Jurassic World | Colin Trevorrow | Chris Pratt, Bryce Dallas Howard |
 When I add this movie to the catalog
 Then I should be able to find it in the catalog @Then("I should be able to find it in the catalog")
 public void shouldBeAbleToFindMovieInCatalog() {
 rest().given().contentType("application/json")
 .get("/movies/{movieId}", movieId)
 .then().statusCode(200)
 .and().body("title", equalTo(newMovie.getTitle()))
 .and().body("director", equalTo(newMovie.getDirector()));
 }
  • 154.
    Feature: Adding newmovies
 In order to sell more movies
 As an online movie seller
 I want to be able to add movies to the catalog
 
 Scenario: Adding movies
 Given the following movie has just come out
 | title | director | actors |
 | Jurassic World | Colin Trevorrow | Chris Pratt, Bryce Dallas Howard |
 When I add this movie to the catalog
 Then I should be able to find it in the catalog @Then("I should be able to find it in the catalog")
 public void shouldBeAbleToFindMovieInCatalog() {
 rest().given().contentType("application/json")
 .get("/movies/{movieId}", movieId)
 .then().statusCode(200)
 .and().body("title", equalTo(newMovie.getTitle()))
 .and().body("director", equalTo(newMovie.getDirector()));
 } Rest Assured + Serenity
  • 155.
    Feature: Adding newmovies
 In order to sell more movies
 As an online movie seller
 I want to be able to add movies to the catalog
 
 Scenario: Adding movies
 Given the following movie has just come out
 | title | director | actors |
 | Jurassic World | Colin Trevorrow | Chris Pratt, Bryce Dallas Howard |
 When I add this movie to the catalog
 Then I should be able to find it in the catalog @Then("I should be able to find it in the catalog")
 public void shouldBeAbleToFindMovieInCatalog() {
 rest().given().contentType("application/json")
 .get("/movies/{movieId}", movieId)
 .then().statusCode(200)
 .and().body("title", equalTo(newMovie.getTitle()))
 .and().body("director", equalTo(newMovie.getDirector()));
 }
  • 156.
    Testing REST serviceswith Rest-Assured
  • 157.
    Testing REST serviceswith Rest-Assured get(“/movies/findByTitle/Gladiator") .then().body("title", equalTo("Gladiator"));
  • 158.
    Testing REST serviceswith Rest-Assured get(“/movies/findByTitle/Gladiator") .then().body("title", equalTo("Gladiator"));
  • 159.
    Testing REST serviceswith Rest-Assured when().get(“/movies/findByTitle/Gladiator”) .then().body("nominations.category", hasItems("Best Actor", "Special Effects"));
  • 160.
    Testing REST serviceswith Rest-Assured when().get(“/movies/findByTitle/Gladiator”) .then().body("nominations.category", hasItems("Best Actor", "Special Effects"));
  • 161.
    Testing REST serviceswith Rest-Assured given().contentType("application/json")
 .content(newMovie)
 .post("/movies")
 .then().statusCode(200)
 .and().extract().jsonPath().getString("id");
  • 162.
    Testing REST serviceswith Rest-Assured given().contentType("application/json")
 .content(newMovie)
 .post("/movies")
 .then().statusCode(200)
 .and().extract().jsonPath().getString("id"); Posting data
  • 163.
    Testing REST serviceswith Rest-Assured Movie matchingMovie = get("/movies/findByTitle/Gladiator").as(Movie.class);
  • 164.
    Testing REST serviceswith Rest-Assured Movie matchingMovie = get("/movies/findByTitle/Gladiator").as(Movie.class); Convert responses to Java objects
  • 165.
    Testing REST serviceswith Rest-Assured given().param("title","Unknown").
 when().get("/movies/search").
 then().statusCode(404);
  • 166.
    Testing REST serviceswith Rest-Assured given().param("title","Unknown").
 when().get("/movies/search").
 then().statusCode(404); Check for errors
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
    57 @ContextConfiguration(loader = SpringApplicationContextLoader.class, classes= MovieServiceApplication.class)
 @WebAppConfiguration
 @IntegrationTest("server.port:0")
 class WhenFindingMovies extends Specification {
 
 @Autowired
 MovieRepository movieRepository;
 
 @Value('${local.server.port}')
 int port;
 
 def setup() {
 movieRepository.deleteAll();
 RestAssured.port = port;
 }
 
 def "should list all movies"() {
 given:
 movieCatalogContains([GLADIATOR, LETTERS_FROM_IWO_JIMA, GRAN_TORINO])
 when:
 def movies = when().get("/movies").as(List)
 then:
 movies.collect {movie -> movie.title} == ["Gladiator", 
 "Letters from Iwo Jima", 
 "Gran Torino"]
 }
  • 172.
    57 @ContextConfiguration(loader = SpringApplicationContextLoader.class, classes= MovieServiceApplication.class)
 @WebAppConfiguration
 @IntegrationTest("server.port:0")
 class WhenFindingMovies extends Specification {
 
 @Autowired
 MovieRepository movieRepository;
 
 @Value('${local.server.port}')
 int port;
 
 def setup() {
 movieRepository.deleteAll();
 RestAssured.port = port;
 }
 
 def "should list all movies"() {
 given:
 movieCatalogContains([GLADIATOR, LETTERS_FROM_IWO_JIMA, GRAN_TORINO])
 when:
 def movies = when().get("/movies").as(List)
 then:
 movies.collect {movie -> movie.title} == ["Gladiator", 
 "Letters from Iwo Jima", 
 "Gran Torino"]
 } Spring Context
  • 173.
    57 @ContextConfiguration(loader = SpringApplicationContextLoader.class, classes= MovieServiceApplication.class)
 @WebAppConfiguration
 @IntegrationTest("server.port:0")
 class WhenFindingMovies extends Specification {
 
 @Autowired
 MovieRepository movieRepository;
 
 @Value('${local.server.port}')
 int port;
 
 def setup() {
 movieRepository.deleteAll();
 RestAssured.port = port;
 }
 
 def "should list all movies"() {
 given:
 movieCatalogContains([GLADIATOR, LETTERS_FROM_IWO_JIMA, GRAN_TORINO])
 when:
 def movies = when().get("/movies").as(List)
 then:
 movies.collect {movie -> movie.title} == ["Gladiator", 
 "Letters from Iwo Jima", 
 "Gran Torino"]
 } Spring Integration Tests
  • 174.
    57 @ContextConfiguration(loader = SpringApplicationContextLoader.class, classes= MovieServiceApplication.class)
 @WebAppConfiguration
 @IntegrationTest("server.port:0")
 class WhenFindingMovies extends Specification {
 
 @Autowired
 MovieRepository movieRepository;
 
 @Value('${local.server.port}')
 int port;
 
 def setup() {
 movieRepository.deleteAll();
 RestAssured.port = port;
 }
 
 def "should list all movies"() {
 given:
 movieCatalogContains([GLADIATOR, LETTERS_FROM_IWO_JIMA, GRAN_TORINO])
 when:
 def movies = when().get("/movies").as(List)
 then:
 movies.collect {movie -> movie.title} == ["Gladiator", 
 "Letters from Iwo Jima", 
 "Gran Torino"]
 } Rest Assured
  • 175.
    57 @ContextConfiguration(loader = SpringApplicationContextLoader.class, classes= MovieServiceApplication.class)
 @WebAppConfiguration
 @IntegrationTest("server.port:0")
 class WhenFindingMovies extends Specification {
 
 @Autowired
 MovieRepository movieRepository;
 
 @Value('${local.server.port}')
 int port;
 
 def setup() {
 movieRepository.deleteAll();
 RestAssured.port = port;
 }
 
 def "should list all movies"() {
 given:
 movieCatalogContains([GLADIATOR, LETTERS_FROM_IWO_JIMA, GRAN_TORINO])
 when:
 def movies = when().get("/movies").as(List)
 then:
 movies.collect {movie -> movie.title} == ["Gladiator", 
 "Letters from Iwo Jima", 
 "Gran Torino"]
 }
  • 176.
  • 177.
  • 178.
  • 179.
    @ContextConfiguration(loader = SpringApplicationContextLoader.class,
 classes= MovieServiceApplication.class)
 @WebAppConfiguration
 @IntegrationTest
 class WhenViewingActorDetailsViaTheController extends Specification {
 
 @Autowired
 ArtistController artistController;
 
 def "should retrieve actor details for an artist"() {
 given:
 movieCatalogContains([GLADIATOR, LETTERS_FROM_IWO_JIMA,
 THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO])
 when:
 Artist artist = artistController.findArtistDetails("Clint Eastwood")
 then:
 artist.name == "Clint Eastwood"
 and:
 artist.filmsActedIn.containsAll(THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO)
 and:
 artist.filmsDirected.containsAll(LETTERS_FROM_IWO_JIMA, GRAN_TORINO)
 }
  • 180.
    @ContextConfiguration(loader = SpringApplicationContextLoader.class,
 classes= MovieServiceApplication.class)
 @WebAppConfiguration
 @IntegrationTest
 class WhenViewingActorDetailsViaTheController extends Specification {
 
 @Autowired
 ArtistController artistController;
 
 def "should retrieve actor details for an artist"() {
 given:
 movieCatalogContains([GLADIATOR, LETTERS_FROM_IWO_JIMA,
 THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO])
 when:
 Artist artist = artistController.findArtistDetails("Clint Eastwood")
 then:
 artist.name == "Clint Eastwood"
 and:
 artist.filmsActedIn.containsAll(THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO)
 and:
 artist.filmsDirected.containsAll(LETTERS_FROM_IWO_JIMA, GRAN_TORINO)
 } Use a fully wired controller
  • 181.
    @ContextConfiguration(loader = SpringApplicationContextLoader.class,
 classes= MovieServiceApplication.class)
 @WebAppConfiguration
 @IntegrationTest
 class WhenViewingActorDetailsViaTheController extends Specification {
 
 @Autowired
 ArtistController artistController;
 
 def "should retrieve actor details for an artist"() {
 given:
 movieCatalogContains([GLADIATOR, LETTERS_FROM_IWO_JIMA,
 THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO])
 when:
 Artist artist = artistController.findArtistDetails("Clint Eastwood")
 then:
 artist.name == "Clint Eastwood"
 and:
 artist.filmsActedIn.containsAll(THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO)
 and:
 artist.filmsDirected.containsAll(LETTERS_FROM_IWO_JIMA, GRAN_TORINO)
 } Use domain objects rather than REST calls
  • 182.
    @ContextConfiguration(loader = SpringApplicationContextLoader.class,
 classes= MovieServiceApplication.class)
 @WebAppConfiguration
 @IntegrationTest
 class WhenViewingActorDetailsViaTheController extends Specification {
 
 @Autowired
 ArtistController artistController;
 
 def "should retrieve actor details for an artist"() {
 given:
 movieCatalogContains([GLADIATOR, LETTERS_FROM_IWO_JIMA,
 THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO])
 when:
 Artist artist = artistController.findArtistDetails("Clint Eastwood")
 then:
 artist.name == "Clint Eastwood"
 and:
 artist.filmsActedIn.containsAll(THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO)
 and:
 artist.filmsDirected.containsAll(LETTERS_FROM_IWO_JIMA, GRAN_TORINO)
 }
  • 183.
  • 184.
  • 185.
    MovieRepository repository
 def artistService
 
 defsetup() {
 repository = Mock(MovieRepository)
 artistService = new ArtistService(movieRepository: repository)
 }
 
 def "should build actor details from films the artist has acted in and has directed"() {
 given: "Clint Eastwood has directed some films"
 repository.findByDirector("Clint Eastwood") >> [LETTERS_FROM_IWO_JIMA, GRAN_TORINO]
 and: "Clint Eastwood has starred in some films"
 repository.findByActors("Clint Eastwood") >> [THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO]
 when:
 def artistDetails = artistService.findArtistByName("Clint Eastwood")
 then:
 artistDetails.isPresent()
 and:
 artistDetails.get().name == "Clint Eastwood" &&
 artistDetails.get().filmsActedIn == [THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO] &&
 artistDetails.get().filmsDirected == [LETTERS_FROM_IWO_JIMA, GRAN_TORINO]
 }
  • 186.
    MovieRepository repository
 def artistService
 
 defsetup() {
 repository = Mock(MovieRepository)
 artistService = new ArtistService(movieRepository: repository)
 }
 
 def "should build actor details from films the artist has acted in and has directed"() {
 given: "Clint Eastwood has directed some films"
 repository.findByDirector("Clint Eastwood") >> [LETTERS_FROM_IWO_JIMA, GRAN_TORINO]
 and: "Clint Eastwood has starred in some films"
 repository.findByActors("Clint Eastwood") >> [THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO]
 when:
 def artistDetails = artistService.findArtistByName("Clint Eastwood")
 then:
 artistDetails.isPresent()
 and:
 artistDetails.get().name == "Clint Eastwood" &&
 artistDetails.get().filmsActedIn == [THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO] &&
 artistDetails.get().filmsDirected == [LETTERS_FROM_IWO_JIMA, GRAN_TORINO]
 } Mocked repositories
  • 187.
    MovieRepository repository
 def artistService
 
 defsetup() {
 repository = Mock(MovieRepository)
 artistService = new ArtistService(movieRepository: repository)
 }
 
 def "should build actor details from films the artist has acted in and has directed"() {
 given: "Clint Eastwood has directed some films"
 repository.findByDirector("Clint Eastwood") >> [LETTERS_FROM_IWO_JIMA, GRAN_TORINO]
 and: "Clint Eastwood has starred in some films"
 repository.findByActors("Clint Eastwood") >> [THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO]
 when:
 def artistDetails = artistService.findArtistByName("Clint Eastwood")
 then:
 artistDetails.isPresent()
 and:
 artistDetails.get().name == "Clint Eastwood" &&
 artistDetails.get().filmsActedIn == [THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO] &&
 artistDetails.get().filmsDirected == [LETTERS_FROM_IWO_JIMA, GRAN_TORINO]
 } Call the service
  • 188.
    MovieRepository repository
 def artistService
 
 defsetup() {
 repository = Mock(MovieRepository)
 artistService = new ArtistService(movieRepository: repository)
 }
 
 def "should build actor details from films the artist has acted in and has directed"() {
 given: "Clint Eastwood has directed some films"
 repository.findByDirector("Clint Eastwood") >> [LETTERS_FROM_IWO_JIMA, GRAN_TORINO]
 and: "Clint Eastwood has starred in some films"
 repository.findByActors("Clint Eastwood") >> [THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO]
 when:
 def artistDetails = artistService.findArtistByName("Clint Eastwood")
 then:
 artistDetails.isPresent()
 and:
 artistDetails.get().name == "Clint Eastwood" &&
 artistDetails.get().filmsActedIn == [THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO] &&
 artistDetails.get().filmsDirected == [LETTERS_FROM_IWO_JIMA, GRAN_TORINO]
 } Check the outcomes
  • 189.
    MovieRepository repository
 def artistService
 
 defsetup() {
 repository = Mock(MovieRepository)
 artistService = new ArtistService(movieRepository: repository)
 }
 
 def "should build actor details from films the artist has acted in and has directed"() {
 given: "Clint Eastwood has directed some films"
 repository.findByDirector("Clint Eastwood") >> [LETTERS_FROM_IWO_JIMA, GRAN_TORINO]
 and: "Clint Eastwood has starred in some films"
 repository.findByActors("Clint Eastwood") >> [THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO]
 when:
 def artistDetails = artistService.findArtistByName("Clint Eastwood")
 then:
 artistDetails.isPresent()
 and:
 artistDetails.get().name == "Clint Eastwood" &&
 artistDetails.get().filmsActedIn == [THE_GOOD_THE_BAD_AND_THE_UGLY, GRAN_TORINO] &&
 artistDetails.get().filmsDirected == [LETTERS_FROM_IWO_JIMA, GRAN_TORINO]
 }
  • 190.
  • 191.
  • 192.
  • 193.
    65 Scenario: Adding movies
 Giventhe following movie has just come out
 | title | director | actors |
 | Jurassic World | Colin Trevorrow | Chris Pratt, Bryce Dallas Howard |
 When I add this movie to the catalog
 Then I should be able to find it in the catalog Executable Specifications Automated tests Living documentation
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
    Living API Documentation
 with Swagger Springfox
  • 200.
  • 201.
    70 @RequestMapping(method = GET)
 @ApiOperation("Listall the movies in the catalog")
 public List<Movie> findAll() {
 return repository.findAll();
 }
 
 @RequestMapping(method = POST)
 @ApiOperation(value = "Add a new movie to the catalog", httpMethod = "POST")
 public Movie add(@RequestBody Movie newMovie) {
 return repository.save(newMovie);
 }
 
 @RequestMapping(value = "/{id}", method = DELETE)
 @ApiOperation(value = "Removing a movie from the catalog", httpMethod = "DELETE")
 public void delete(@PathVariable String id) {
 repository.delete(id);
 }
 Springfox Some annotations… Swagger and Spring Boot
  • 202.
    70 @RequestMapping(method = GET)
 @ApiOperation("Listall the movies in the catalog")
 public List<Movie> findAll() {
 return repository.findAll();
 }
 
 @RequestMapping(method = POST)
 @ApiOperation(value = "Add a new movie to the catalog", httpMethod = "POST")
 public Movie add(@RequestBody Movie newMovie) {
 return repository.save(newMovie);
 }
 
 @RequestMapping(value = "/{id}", method = DELETE)
 @ApiOperation(value = "Removing a movie from the catalog", httpMethod = "DELETE")
 public void delete(@PathVariable String id) {
 repository.delete(id);
 }
 Springfox Some annotations… Swagger and Spring Boot
  • 203.
    70 @RequestMapping(method = GET)
 @ApiOperation("Listall the movies in the catalog")
 public List<Movie> findAll() {
 return repository.findAll();
 }
 
 @RequestMapping(method = POST)
 @ApiOperation(value = "Add a new movie to the catalog", httpMethod = "POST")
 public Movie add(@RequestBody Movie newMovie) {
 return repository.save(newMovie);
 }
 
 @RequestMapping(value = "/{id}", method = DELETE)
 @ApiOperation(value = "Removing a movie from the catalog", httpMethod = "DELETE")
 public void delete(@PathVariable String id) {
 repository.delete(id);
 }
 Springfox Some annotations… Swagger and Spring Boot
  • 204.
    70 @RequestMapping(method = GET)
 @ApiOperation("Listall the movies in the catalog")
 public List<Movie> findAll() {
 return repository.findAll();
 }
 
 @RequestMapping(method = POST)
 @ApiOperation(value = "Add a new movie to the catalog", httpMethod = "POST")
 public Movie add(@RequestBody Movie newMovie) {
 return repository.save(newMovie);
 }
 
 @RequestMapping(value = "/{id}", method = DELETE)
 @ApiOperation(value = "Removing a movie from the catalog", httpMethod = "DELETE")
 public void delete(@PathVariable String id) {
 repository.delete(id);
 }
 Springfox Some annotations… Swagger and Spring Boot
  • 205.
    71 Springfox @EnableAutoConfiguration
 @EnableSwagger2
 public class MovieServiceApplication{
 
 public static void main(String[] args) {
 SpringApplication.run(MovieServiceApplication.class, args);
 }
 
 @Bean
 public Docket moviesApi() {
 return new Docket(DocumentationType.SWAGGER_2)
 .select()
 .apis(RequestHandlerSelectors.any())
 .paths(PathSelectors.any())
 .build()
 .pathMapping("/")
 .directModelSubstitute(LocalDate.class, String.class)
 .genericModelSubstitutes(ResponseEntity.class);
 }
 } Some configuration… Swagger and Spring Boot
  • 206.
  • 207.
  • 208.
    Automated MonitoringFast provisioningAfast deployment pipeline So you want to micro-service?
  • 209.
    Automated health checksRealoperationsSmoke tests in production Simple checks may not be enough
  • 210.
    An example withSpring Actuator @Component
 public class CatalogHealth implements HealthIndicator {
 
 @Autowired
 MovieRepository movieRepository;
 
 @Override
 public Health health() {
 return (isCatalogStocked()) ? 
 Health.status(new Status("UP", "Movie count: " + movieRepository.count())).build() 
 : Health.down().build();
 }
 
 private boolean isCatalogStocked() {
 return (movieRepository.count() > 0);
 }
 }
  • 211.
    An example withSpring Actuator @Component
 public class CatalogHealth implements HealthIndicator {
 
 @Autowired
 MovieRepository movieRepository;
 
 @Override
 public Health health() {
 return (isCatalogStocked()) ? 
 Health.status(new Status("UP", "Movie count: " + movieRepository.count())).build() 
 : Health.down().build();
 }
 
 private boolean isCatalogStocked() {
 return (movieRepository.count() > 0);
 }
 } A Spring Actuator Health Check
  • 212.
    An example withSpring Actuator @Component
 public class CatalogHealth implements HealthIndicator {
 
 @Autowired
 MovieRepository movieRepository;
 
 @Override
 public Health health() {
 return (isCatalogStocked()) ? 
 Health.status(new Status("UP", "Movie count: " + movieRepository.count())).build() 
 : Health.down().build();
 }
 
 private boolean isCatalogStocked() {
 return (movieRepository.count() > 0);
 }
 } A Spring Actuator Health Check Custom logic to decide if the app is working
  • 213.
    An example withSpring Actuator @Component
 public class MovieTransactionHealth implements HealthIndicator {
 
 @Autowired
 MovieController movieController;
 
 @Override
 public Health health() {
 return Health.status(transactionStatus()).build();
 }
 
 private Status transactionStatus() {
 try {
 Movie movie = new Movie("TEST title", "TEST description", "TEST director", ImmutableList.of("TEST actor"));
 Movie reloadedMovie = movieController.add(movie);
 movieController.delete(reloadedMovie.getId());
 return Status.UP;
 } catch (Throwable e) {
 return new Status("DOWN", e.toString());
 }
 }
 }
  • 214.
    An example withSpring Actuator @Component
 public class MovieTransactionHealth implements HealthIndicator {
 
 @Autowired
 MovieController movieController;
 
 @Override
 public Health health() {
 return Health.status(transactionStatus()).build();
 }
 
 private Status transactionStatus() {
 try {
 Movie movie = new Movie("TEST title", "TEST description", "TEST director", ImmutableList.of("TEST actor"));
 Movie reloadedMovie = movieController.add(movie);
 movieController.delete(reloadedMovie.getId());
 return Status.UP;
 } catch (Throwable e) {
 return new Status("DOWN", e.toString());
 }
 }
 } More complex custom logic
  • 215.
    An example withSpring Actuator @Component
 public class MovieTransactionHealth implements HealthIndicator {
 
 @Autowired
 MovieController movieController;
 
 @Override
 public Health health() {
 return Health.status(transactionStatus()).build();
 }
 
 private Status transactionStatus() {…}
 } @Component
 public class CatalogHealth implements HealthIndicator {
 
 @Autowired
 MovieRepository movieRepository;
 
 @Override
 public Health health() {
 return (isCatalogStocked()) ? 
 Health.status(new Status("UP", "Movie count: " + 
 movieRepository.count())).build() 
 : Health.down().build();
 }
 
 private boolean isCatalogStocked() {…}
 }
  • 216.
    Try all thisout at home! Install Gradle Install MongoDB Clone the repowakaleo/movie-service
  • 217.