JDD2014: Behaviour driven development, BDD, with cucumber for JAVA - Thomas Sundberg
Behavior driven integration with Cucumber & Citrus
-
Upload
christophd -
Category
Software
-
view
110 -
download
1
Transcript of Behavior driven integration with Cucumber & Citrus
#DevoxxUS
Behavior driven integration
with Cucumber & Citrus
Christoph Deppisch ConSol Software GmbH
@cucumberbdd @citrus_test
#DevoxxUS @citrus_test
http://cucumber.io
http://citrusframework.org
@cucumberbdd
#DevoxxUS
Behavior Driven Development
@citrus_test@cucumberbdd
#DevoxxUS
Communication
@citrus_test@cucumberbdd
#DevoxxUS @citrus_test
=
@cucumberbdd
#DevoxxUS
Explaining the behavior
@citrus_test@cucumberbdd
#DevoxxUS
Concrete Examples
@citrus_test@cucumberbdd
#DevoxxUS
Given a certain context When some event happens
Then an outcome should occur
@citrus_test
Gherkin
@cucumberbdd
#DevoxxUS
Voting application
@citrus_test@cucumberbdd
#DevoxxUS
Feature specificationFeature: Create voting As a user I want to create new votings. Each voting is given default vote options. Scenario: Default voting options Given voting title "Do you like Mondays?" When I create new voting Then voting should have 2 options And voting should have option "yes" And voting should have option „no" And voting title should be "Do you like Mondays?"
@citrus_test@cucumberbdd
#DevoxxUS
Feature specification continuedFeature: Create voting As a user I want to create new votings. Each voting is given default vote options. The user should be able to set custom vote options. Scenario: Default voting options Given voting title "Do you like Mondays?" When I create new voting Then voting should have 2 options And voting should have option "yes" And voting should have option „no" And voting title should be "Do you like Mondays?" Scenario: Custom voting options When I create new voting "What is your favorite color?" And voting options are "green:red:blue" Then voting title should be "What is your favorite color?" And voting should have options | green | | red | | blue |
@citrus_test@cucumberbdd
#DevoxxUS @citrus_test@cucumberbdd
#DevoxxUS
JUnit Cucumber test@RunWith(Cucumber.class) public class VotingFeatureTest {}
@citrus_test
voting-close.feature voting-create.feature voting-results.feature
public class VotingSteps { @Given("^New default voting$") public void defaultVoting() { ... } @When("^I create new voting \"(.+)\"$") public void createVotingWithTitle(String title) { ... } @Then("^voting should have (\\d+) options$") public void votingShouldHaveOptions(int optionCount) { ... } }
@cucumberbdd
#DevoxxUS
Step definitions
@When("^I create new voting \"(.+)\"$") public void createVotingWithTitle(String title) { votingId = UUID.randomUUID(); Voting voting = new Voting(votingId, title); votingService.add(voting);}
@citrus_test
@Then("^voting should have (\\d+) options$") public void votingShouldHaveOptions(int optionCount) { Assert.assertEquals(optionCount, votingService.get(votingId).getOptions().size());}
When I create new voting "What is your favorite color?"
Then voting should have 3 options
@cucumberbdd
#DevoxxUS
Data tables
@Then("^(?:the )?voting should have options$") public void votingShouldHaveOptions(DataTable dataTable) { List<String> options = dataTable.asList(String.class); votingShouldHaveOptions(options.size()); for(String option : options) { votingShouldHaveOption(option); }}
@citrus_test
Then voting should have options| green | | red | | blue |
@cucumberbdd
#DevoxxUS @citrus_test
Demo
@cucumberbdd
#DevoxxUS
Hooks@Beforepublic void before(Scenario scenario) { // do something} @Afterpublic void after(Scenario scenario) { // do something}
@citrus_test@cucumberbdd
#DevoxxUS
BackgroundFeature: Show voting results As a user I want to vote for an option. All voting results are stored and the user should be able to get top vote option for each voting. Background: Given I create new voting "Do you like cucumbers?" And voting options are "yes:no" Scenario: Initial vote results Then votes of option "yes" should be 0 And votes of option "no" should be 0 Scenario: Get vote results When I vote for "yes" Then votes of option "yes" should be 1 And votes of option "no" should be 0 And top vote should be "yes"
@citrus_test@cucumberbdd
#DevoxxUS
Scenario OutlineFeature: Show voting results As a user I want to vote for an option. All voting results are stored and the user should be able to get top vote option for each voting. Scenario Outline: Get vote results Given I create new voting "<title>" And voting options are "yes:no" When I vote for "yes" <yes_votes> times And I vote for "no" <no_votes> times Then votes of option "yes" should be <yes_votes> And votes of option "no" should be <no_votes> And top vote should be "<top_vote>"
Examples: | title | yes_votes | no_votes | top_vote | | Do you like hotdogs? | 12 | 5 | yes | | Do you like crap sandwiches? | 1 | 25 | no |
@citrus_test@cucumberbdd
#DevoxxUS @citrus_test@cucumberbdd
#DevoxxUS
Messaging Integration
@citrus_test@cucumberbdd
#DevoxxUS @citrus_test
Client VotingAppHttp REST
JMS
Reporting
MailServer
JMS
SMTP
@cucumberbdd
#DevoxxUS @citrus_test
VotingAppHttp REST
JMS
JMS
SMTP
@cucumberbdd
#DevoxxUS
Citrus Object Factory
cucumber.api.java.ObjectFactory=cucumber.runtime.java.CitrusObjectFactory
@citrus_test
cucumber.properties
@RunWith(Cucumber.class) @CucumberOptions(plugin = { "com.consol.citrus.cucumber.CitrusReporter" } )public class VotingRestFeatureIT { }
@cucumberbdd
#DevoxxUS
Messaging FeatureFeature: Voting Http REST API Background: Given Voting list is empty And New voting "Do you like donuts?" And voting options are "yes:no" Scenario: Top vote When client creates the voting And client votes for "no" Then votes should be | yes | 0 | | no | 1 | And top vote should be "no" Scenario: Close voting Given reporting is enabled When client creates the voting And client votes for "yes" 3 times And client votes for "no" 2 times And client closes the voting Then participants should receive reporting mail"""Dear participants,the voting '${title}' came to an end.The top answer is 'yes'!Have a nice day!Your Voting-App Team"""
@citrus_test@cucumberbdd
#DevoxxUS
Endpoint injection
public class VotingRestSteps { @CitrusEndpoint private HttpClient votingClient;
@CitrusEndpoint private MailServer mailServer; @CitrusResource private TestRunner runner; @Given("^Voting list is empty$") public void clear() { runner.http(action -> action.client(votingClient) .send() .delete("/voting")); runner.http(action -> action.client(votingClient) .receive() .response(HttpStatus.OK)); } }
@citrus_test@cucumberbdd
#DevoxxUS
Endpoint configuration
@Configurationpublic class CitrusEndpointConfig { @Bean public HttpClient votingClient() { return CitrusEndpoints.http() .client() .requestUrl("http://localhost:8080/rest/services") .build(); } @Bean public MailServer mailServer() { return CitrusEndpoints.mail() .server() .port(2222) .autoStart(true) .autoAccept(true) .build(); }}
@citrus_test@cucumberbdd
#DevoxxUS
Citrus endpoints
Component Descriptioncitrus-http Http REST client and servercitrus-jms JMS queue or topic destinationcitrus-ws SOAP client and server
citrus-mail SMTP mail client and servercitrus-docker Docker container managementcitrus-camel Apache Camel endpoint
citrus-selenium Selenium browser endpointcitrus-vertx Vert.x endpoint
citrus-kubernetes Kubernetes client…
@cucumberbdd @citrus_test
#DevoxxUS
Http REST messaging@Given("^New voting \"([^\"]+)\"$") public void newVoting(String title) { runner.variable("id", "citrus:randomUUID()"); runner.variable("title", title); runner.variable("options", buildOptionsAsJsonArray("yes:no")); runner.variable("closed", false);} @When("^client creates the voting$") public void createVoting() { runner.http(action -> action.client(votingClient) .send() .post("/voting") .contentType("application/json") .payload("{ \"id\": \"${id}\", \"title\": \"${title}\", \"options\": ${options} }")); runner.http(action -> action.client(votingClient) .receive() .response(HttpStatus.OK) .messageType(MessageType.JSON));}
@citrus_test@cucumberbdd
#DevoxxUS
Mail SMTP messaging@Then("^participants should receive reporting mail$") public void shouldReceiveReportingMail(String text) { runner.createVariable("mailBody", text); runner.receive(action -> action.endpoint(mailServer) .payload(new ClassPathResource("templates/mail.xml")) .header(CitrusMailMessageHeaders.MAIL_SUBJECT, "Voting results") .header(CitrusMailMessageHeaders.MAIL_FROM, "[email protected]") .header(CitrusMailMessageHeaders.MAIL_TO, "[email protected]"));}
@citrus_test
<mail-message xmlns="http://www.citrusframework.org/schema/mail/message"> <from>[email protected]</from> <to>[email protected]</to> <cc></cc> <bcc></bcc> <subject>Voting results</subject> <body> <contentType>text/plain; charset=us-ascii</contentType> <content>${mailBody}</content> </body> </mail-message>
@cucumberbdd
#DevoxxUS
JMS messaging
@CitrusEndpoint(name = "reportingEndpoint") private JmsEndpoint reportingEndpoint;
@Then("^reporting should receive vote results$") public void shouldReceiveReport(DataTable dataTable) { runner.createVariable("results", buildOptionsAsJsonArray(dataTable)); runner.receive(action -> action.endpoint(reportingEndpoint) .messageType(MessageType.JSON) .payload("{ \"id\": \"${id}\", \"title\": \"${title}\", \"options\": ${results} }"));}
@citrus_test
@Beanpublic JmsEndpoint reportingEndpoint() { return CitrusEndpoints.jms() .asynchronous() .connectionFactory(connectionFactory()) .destination("jms.voting.report") .build();}
@cucumberbdd
#DevoxxUS @citrus_test
Demo
@cucumberbdd
#DevoxxUS
Reading & information
https://cucumber.io
http://citrusframework.org
Demo Sources
https://github.com/christophd/citrus-demo-devoxx-us
Citrus Cucumber Extension
http://citrusframework.org/reference/html/cucumber.html
@citrus_test@cucumberbdd
#DevoxxUS @citrus_test
Thank You!
@cucumberbdd