testing microservices with a citrus twist
TRANSCRIPT
@citrus_test#Devoxx #CitrusTwist
Testing Microservices with a Citrus Twist
Christoph Deppisch ConSol* Software GmbH
@citrus_test#Devoxx #CitrusTwist
Christoph Deppisch
• Senior software developer
• @ConSol* Munich, Germany
• 10 years of experience in Java
• Passionate about automated software testing
• Founder of the Open Source framework Citrus
• Happy to be here today! Twitter: @freaky_styley
@citrus_test#Devoxx #CitrusTwist
What is Citrus?
• Open Source integration test framework
• Focus on messaging in distributed software systems
• Automated interface tests
• Ready-to-use endpoint components for message exchange
• Works & integrates with well-known libraries
• TestNG, JUnit
• Apache Camel, Spring, Docker, Arquillian …
@citrus_test#Devoxx #CitrusTwist
Integration
@citrus_test#Devoxx #CitrusTwist
Every project needs integration tests!
@citrus_test#Devoxx #CitrusTwist
Service A Service BInterface
REST, JMS, File, SOAP
@citrus_test#Devoxx #CitrusTwist
Service A Service BInterface
REST, JMS, File, SOAP
Mock?Simulator?
@citrus_test#Devoxx #CitrusTwist
Service AInterface
REST, JMS, File, SOAP
@citrus_test#Devoxx #CitrusTwist
Microservices
@citrus_test#Devoxx #CitrusTwist
Service
Service
Service
Service
Service
ServiceServiceService
External
External
@citrus_test#Devoxx #CitrusTwist
Continuous Delivery
@citrus_test#Devoxx #CitrusTwist
Automation!
@citrus_test#Devoxx #CitrusTwist
Citrus integration twist
@citrus_test#Devoxx #CitrusTwist
import com.consol.citrus.annotations.CitrusTest; import com.consol.citrus.dsl.testng.TestNGCitrusTestDesigner; import org.testng.annotations.Test;
@Testpublic class SampleCitrusIT extends TestNGCitrusTestDesigner { @CitrusTest public void sayHello() { echo("Hello, Devoxx! This is my first Citrus test!"); } }
@citrus_test#Devoxx #CitrusTwist
Test actions
@citrus_test#Devoxx #CitrusTwist
• Missing something? Adding custom actions is possible!
Test actionsTest action Description
echo Log message to consolesend Sends a message
receive Receives a messagesleep Wait some time
sql Execute SQL statementsparallel Execute actions in parallel
conditional Execute actions based on conditioniterate Execute actions in iteration
repeat-on-error Failsafe action execution…
@citrus_test#Devoxx #CitrusTwist
@Testpublic class MessageExchangeIT extends TestNGCitrusTestDesigner { @Autowired private Endpoint orderEndpoint; @CitrusTest public void sendAndReceiveMessage() { send(orderEndpoint) .payload("...");
receive(orderEndpoint) .payload("..."); } }
@citrus_test#Devoxx #CitrusTwist
@CitrusTestpublic void sendAndReceiveMessage() { variable("orderId", Functions.randomNumber(10L));
send(orderEndpoint) .payload("<order>" +
"<id>${orderId}</id>" + "</order>") .header("operation", "placeOrder") .header("id", "${orderId}");
receive(orderEndpoint) .payload("<orderResponse>" + "<timestamp>@ignore@</timestamp>" + "<id>${orderId}</id>" + "<success>true</success>" + "</orderResponse>") .header("id", "${orderId}"); }
@citrus_test#Devoxx #CitrusTwist
Endpoints
@citrus_test#Devoxx #CitrusTwist
• Missing something? Adding custom components is easy!
Endpoint componentsComponent 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-ftp FTP client and servercitrus-vertx Vert.x endpointcitrus-ssh SSH client and server
…
@citrus_test#Devoxx #CitrusTwist
<!-- JMS endpoints --> <citrus-jms:endpoint id="orderEndpoint" destination-name="factory.order.inbound"/> <citrus-jms:sync-endpoint id="errorEndpoint" destination-name="base.error.service" timeout="${global.receive.timeout}"/>
<!-- JMS connection factory and message broker --><bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> <property name="brokerURL" value="tcp://localhost:61616" /></bean>
Endpoints: citrus-jms
@citrus_test#Devoxx #CitrusTwist
<!-- REST Http client --> <citrus-http:client id="reportingClient" request-method="GET" timeout="5000" request-url="http://localhost:8080/services/report"/>
<!-- REST Http server --><citrus-http:server id="reportingServer" port="8080" auto-start="true"/>
Endpoints: citrus-http
@citrus_test#Devoxx #CitrusTwist
Example
@citrus_test#Devoxx #CitrusTwist
Cookie factory sample
worker
worker
worker
webapp reporting2x 4x 1x
@citrus_test#Devoxx #CitrusTwist
Docker infrastructure
brokerwebapp report
worker
worker
worker
@citrus_test#Devoxx #CitrusTwist
brokerwebapp report
worker
worker
worker
@citrus_test#Devoxx #CitrusTwist
Demo
@citrus_test#Devoxx #CitrusTwist
Demo tools
• docker-maven-plugin
• docker:build, docker:start, docker:stop
• https://github.com/rhuss/docker-maven-plugin
• Apache Camel
• Content-based routing, REST endpoints, standalone worker
• http://camel.apache.org/
• Demo Code
• https://github.com/christophd/citrus-demo-devoxx
@citrus_test#Devoxx #CitrusTwist
brokerwebapp report
worker
worker
worker
@citrus_test#Devoxx #CitrusTwist
brokerwebapp report
@citrus_test#Devoxx #CitrusTwist
broker
worker
worker
worker
@citrus_test#Devoxx #CitrusTwist
brokerwebapp report
@citrus_test#Devoxx #CitrusTwist
What else?
@citrus_test#Devoxx #CitrusTwist
What else!?
• Docker integration
• build, start, stop, inspect, …
• Manage Docker containers at test runtime
• Arquillian extension
• Use Citrus in Arquillian test
• @CitrusFramework, @CitrusEndpoint, @CitrusResource
• Apache Camel integration
• Create, start, stop routes at test runtime
@citrus_test#Devoxx #CitrusTwist
Information
• Homepage • http://citrusframework.org
• Blog • http://labs.consol.de/tags/citrus/
• User Guide • http://citrusframework.org/reference/html/index.html
• Mailing List • [email protected]
@citrus_test#Devoxx #CitrusTwist
Questions!?