Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Arquillian & Citrus

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers. →

Arquillian & Citrus

JavaLand 2016

Avatar for Christoph Deppisch

Christoph Deppisch

March 09, 2016

More Decks by Christoph Deppisch

Other Decks in Technology

Transcript

  1. SPEAKER CHRISTOPH DEPPISCH ▸ Senior software developer ▸ @ConSol* Munich,

    Germany ▸ 10 years of experience in Java ▸ Passionate about automated software testing ▸ Founder of the OpenSource framework Citrus @freaky_styley
  2. ARQUILLIAN & CITRUS BOTH TOOLS ARE ▸ Test frameworks ▸

    Written in Java ▸ Automated integration & acceptance tests ▸ OpenSource
  3. INTEGRATION TESTS WHAT ARE INTEGRATION TESTS? Unit Integration Focus: small

    software units No dependencies Test in isolation Mocks Low-Level Focus: interaction of units Dependencies Messaging interfaces Simulators High-Level
  4. INTEGRATION TESTS INTEGRATION SETUP APPLICATION SERVER SYSTEM UNDER TEST CLIENTS

    SERVER CLIENTS CLIENTS SERVER SERVER RESOURCES SERVICES CONFIGURATION DB
  5. INTEGRATION TESTS INTEGRATION CHALLENGES ▸ Infrastructure setup ▸ Dependencies ▸

    to other applications (messaging) ▸ to Mail-servers, FTP-servers, LDAP-servers ▸ to JMS message broker ▸ … ▸ Test execution slow
  6. INTEGRATION TESTS WHY ARE WE DOING THIS? ▸ Consequences of

    mocking and isolation in Unit tests ▸ Untested configuration ▸ Untested dependency injection ▸ Untested messaging interfaces ▸ We need to test ▸ Non-functional requirements (Logging, Monitoring, Configuration, …) ▸ Security (Authorization, Authentication, Certificates) ▸ Reliability (Failover, High Availability)
  7. ARQUILLIAN GOALS ▸ Don’t mock me. Write real tests! ▸

    In-container tests ▸ Container lifecycle management ▸ Archive deployment ▸ Dependency injection ▸ Access to managed resources
  8. ARQUILLIAN CONTAINER MODE ▸ Remote ▸ completely separate container ▸

    Managed ▸ separate JVM, but Arquillian managed ▸ Embedded ▸ same JVM process as Arquillian ▸ Embedded is the fastest - but no class path separation
  9. ARQUILLIAN MAVEN DEPENDENCIES <dependencies> 
 <dependency>
 <groupId>org.jboss.arquillian</groupId>
 <artifactId>arquillian-bom</artifactId>
 <version>${arquillian.version}</version>
 <scope>import</scope>


    <type>pom</type>
 </dependency> <dependency>
 <groupId>junit</groupId>
 <artifactId>junit</artifactId>
 <version>${junit.version}</version>
 <scope>test</scope>
 </dependency>
 
 <dependency>
 <groupId>org.jboss.arquillian.junit</groupId>
 <artifactId>arquillian-junit-container</artifactId>
 <version>${arquillian.version}</version>
 <scope>test</scope>
 </dependency> </dependencies>
  10. CONTAINER CONFIGURATION <profile>
 <id>wildfly-managed-arquillian</id>
 <properties>
 <serverRoot>${project.build.directory}/wildfly-${wildfly.version}</serverRoot>
 </properties>
 <dependencies>
 <dependency>
 <groupId>org.wildfly.arquillian</groupId>


    <artifactId>wildfly-arquillian-container-managed</artifactId>
 <version>1.0.2.Final</version>
 <scope>test</scope>
 </dependency>
 </dependencies>
 <build>
 <plugins>
 <plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-dependency-plugin</artifactId>
 <executions>
 <execution>
 <id>wildfly-unpack</id>
 <phase>generate-test-resources</phase>
 <goals>
 <goal>unpack</goal>
 </goals>
 [...]
 </execution>
 </executions>
 </plugin>
 </plugins>
 </build>
 </profile>
  11. <?xml version="1.0" encoding="UTF-8"?>
 <arquillian xmlns="http://jboss.org/schema/arquillian" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation=" http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
 


    <defaultProtocol type="Servlet 3.0"/>
 
 <container qualifier="wildfly-managed" default="true">
 <configuration>
 <property name="jbossHome">${jboss.home}</property>
 <property name="serverConfig">standalone.xml</property>
 <property name="allowConnectingToRunningServer">true</property>
 </configuration>
 </container>
 
 </arquillian> CITRUS EXTENSION ARQUILLIAN.XML
  12. ARQUILLIAN EXAMPLE @RunWith(Arquillian.class)
 @RunAsClient
 public class EmployeeResourceTest {
 
 @ArquillianResource


    private URL baseUri;
 
 @Deployment
 public static WebArchive createDeployment() {
 [...]
 }
 
 @Test
 public void testGet() { WebTarget webTarget = ClientBuilder.newClient().target( URI.create(new URL(baseUri, "registry/employee").toExternalForm()));
 webTarget.register(Employee.class); 
 Employee employee = webTarget
 .path("{id}")
 .resolveTemplate("id", "1")
 .request(MediaType.APPLICATION_XML)
 .get(Employee.class);
 assertEquals("Leonard", employee.getName());
 assertEquals(21, employee.getAge());
 }
 }
  13. ARQUILLIAN MICRO DEPLOYMENTS ▸ ShrinkWrap archives ▸ Include only the

    needed classes and dependencies ▸ Faster deployments @Deployment
 public static WebArchive createDeployment() {
 return ShrinkWrap.create(WebArchive.class)
 .addClasses(Employees.class, Employee.class, EmployeeRepository.class)
 .addPackage(SmsGateway.class.getPackage())
 .addAsLibraries(Maven.configureResolver()
 .workOffline(true)
 .resolve(CXF_GROUP_ID + ":cxf-rt-frontend-jaxws:" + CXF_VERSION,
 CXF_GROUP_ID + ":cxf-rt-transports-http:" + CXF_VERSION)
 .withTransitivity()
 .asFile()); }
  14. JAVALAND DEMO APPLICATION DEMO APPLICATION ▸ Employee registry demo ▸

    https://github.com/christophd/citrus-demo-javaland WILDFLY CONTAINER EMPLOYEE REGISTRY ARQUILLIAN
 TEST RESOURCES SERVICES CONFIGURATION REST API
  15. ARQUILLIAN SUMMARY ▸ Arquillian makes it easy to run in-container

    tests ▸ Container lifecycle management ▸ Micro-deployments ▸ Access to container-managed resources ▸ Runs via command line or Java IDE
  16. CITRUS GOALS ▸ Test messaging interfaces ▸ Simulate messaging ▸

    Sync/Async ▸ Client/Server ▸ Ready to use components ▸ Http REST, SOAP, JMS, FTP, RMI, JMX, …
  17. JAVALAND DEMO APPLICATION DEMO APPLICATION ▸ Employee registry demo ▸

    https://github.com/christophd/citrus-demo-javaland MAIL SERVER WILDFLY CONTAINER EMPLOYEE REGISTRY ARQUILLIAN
 TEST RESOURCES SERVICES CONFIGURATION REST API MAIL SMS 
 GATEWAY SOAP
  18. CITRUS MAVEN DEPENDENCIES <dependency>
 <groupId>com.consol.citrus</groupId>
 <artifactId>citrus-core</artifactId>
 <version>${citrus.version}</version>
 <scope>test</scope>
 </dependency>
 <dependency>


    <groupId>com.consol.citrus</groupId>
 <artifactId>citrus-java-dsl</artifactId>
 <version>${citrus.version}</version>
 <scope>test</scope>
 </dependency>
 <dependency>
 <groupId>com.consol.citrus</groupId>
 <artifactId>citrus-arquillian</artifactId>
 <version>${citrus.version}</version>
 <scope>test</scope>
 </dependency> 
 <dependency>
 <groupId>com.consol.citrus</groupId>
 <artifactId>citrus-mail</artifactId>
 <version>${citrus.version}</version>
 <scope>test</scope>
 </dependency>
  19. <?xml version="1.0" encoding="UTF-8"?>
 <arquillian xmlns="http://jboss.org/schema/arquillian" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation=" http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
 


    <defaultProtocol type="Servlet 3.0"/>
 
 <container qualifier="wildfly-managed" default="true">
 <configuration>
 <property name="jbossHome">${jboss.home}</property>
 <property name="serverConfig">standalone.xml</property>
 <property name="allowConnectingToRunningServer">true</property>
 </configuration>
 </container>
 
 <extension qualifier="citrus">
 <property name="autoPackage">false</property>
 <property name=„citrusVersion">2.5.1</property>
 </extension> 
 </arquillian> CITRUS EXTENSION ARQUILLIAN.XML
  20. ADDING CITRUS TO ARQUILLIAN @RunWith(Arquillian.class)
 @RunAsClient
 public class EmployeeResourceTest {


    
 @CitrusFramework
 private Citrus citrusFramework;
 
 @ArquillianResource
 private URL baseUri;
 
 @Deployment(testable = false)
 public static WebArchive createDeployment() {
 return Deployments.employeeWebRegistry();
 }
 
 @Test
 @CitrusTest
 public void testGetSingle(@CitrusResource TestDesigner citrus) { String serviceUri = new URL(baseUri, "").toExternalForm(); 
 citrus.http().client(serviceUri)
 .get("/registry/employee/1")
 .accept(MediaType.APPLICATION_XML);
 
 citrus.http().client(serviceUri)
 .response(HttpStatus.OK)
 .payload("<employee><age>21</age><name>Leonard</name></employee>");
 
 citrusFramework.run(citrus.getTestCase());
 }
 }
  21. TEST ACTIONS TEST ACTIONS Action Description echo Log message to

    console send Sends a message receive Receives a message sleep Wait some time sql Execute SQL statements parallel Execute actions in parallel conditional Execute actions based on iterate Execute actions in iteration repeat-on-error Failsafe action execution …
  22. @CitrusEndpoint
 private MailServer mailServer;
 
 @Test
 @CitrusTest
 public void testPostWithWelcomeEmail(@CitrusResource

    TestDesigner citrus) {
 citrus.variable("employee.name", "Rajesh");
 citrus.variable("employee.age", "20");
 citrus.variable("employee.email", "[email protected]");
 
 citrus.http().client(serviceUri)
 .post()
 .fork(true)
 .contentType(MediaType.APPLICATION_FORM_URLENCODED)
 .payload("name=${employee.name}&age=${employee.age}" + "&email=${employee.email}");
 
 citrus.receive(mailServer)
 .payload(new ClassPathResource("templates/welcome-mail.xml"))
 .header(CitrusMailMessageHeaders.MAIL_SUBJECT, "Welcome new employee")
 .header(CitrusMailMessageHeaders.MAIL_TO, "${employee.email}");
 
 citrus.send(mailServer)
 .payload(new ClassPathResource("templates/welcome-mail-response.xml"));
 
 citrus.http().client(serviceUri)
 .response(HttpStatus.NO_CONTENT);
 
 citrusFramework.run(citrus.getTestCase());
 } CITRUS BY EXAMPLE
  23. <mail-message xmlns="http://www.citrusframework.org/schema/mail/message">
 <from>[email protected]</from>
 <to>${employee.email}</to>
 <cc></cc>
 <bcc></bcc>
 <subject>Welcome new employee</subject>
 <body>


    <contentType>text/plain; charset=us-ascii</contentType>
 <content> We welcome you '${employee.name}' to our company - now get to work! </content>
 </body>
 </mail-message> WELCOME MAIL CONTENT WELCOME-MAIL.XML WELCOME-MAIL-RESPONSE.XML <mail-response xmlns="http://www.citrusframework.org/schema/mail/message">
 <code>250</code>
 <message>OK</message>
 </mail-response>
  24. CITRUS ENDPOINT CONFIGURATION CITRUS-CONTEXT.XML <beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:citrus="http://www.citrusframework.org/schema/config"
 xmlns:citrus-soap="http://www.citrusframework.org/schema/ws/config"
 xmlns:citrus-mail="http://www.citrusframework.org/schema/mail/config"


    xsi:schemaLocation="...">
 
 <citrus:schema-repository id="schemaRepository">
 <citrus:locations>
 <citrus:location path="classpath:wsdl/SmsGateway.wsdl"/>
 </citrus:locations>
 </citrus:schema-repository>
 <!-- Sms Gateway SOAP server -->
 <citrus-soap:server id="smsGatewayServer"
 auto-start="true"
 port="18008"
 timeout=„5000"/> 
 <!-- Mail server mock -->
 <citrus-mail:server id="mailServer"
 auto-start="true"
 port="2222"/>
 </beans>
  25. @CitrusEndpoint
 private WebServiceServer smsGatewayServer;
 
 @Test
 @CitrusTest
 public void testPostWithWelcomeSms(@CitrusResource

    TestDesigner citrus) {
 citrus.variable("employee.name", "Bernadette");
 citrus.variable("employee.age", "24");
 citrus.variable("employee.mobile", "4915199999999");
 
 citrus.http().client(serviceUri)
 .post()
 .fork(true)
 .contentType(MediaType.APPLICATION_FORM_URLENCODED)
 .payload("name=${employee.name}&age=${employee.age}" + "&mobile=${employee.mobile}");
 
 citrus.receive(smsGatewayServer)
 .payload(new ClassPathResource("templates/send-sms-request.xml"));
 
 citrus.send(smsGatewayServer)
 .payload(new ClassPathResource("templates/send-sms-response.xml"));
 
 citrus.http().client(serviceUri)
 .response(HttpStatus.NO_CONTENT);
 
 citrusFramework.run(citrus.getTestCase());
 } SMS GATEWAY TEST
  26. <sms:SendSmsRequest xmlns:sms="http://www.smsgateway.org/schema/SmsGateway/v1">
 <sms:communicationId>@variable('communicationId')@</sms:communicationId>
 <sms:msisdn>${employee.mobile}</sms:msisdn>
 <sms:text>Welcome on board '${employee.name}' - now

    get to work!</sms:text>
 </sms:SendSmsRequest> SMS REQUEST CONTENT SEND-SMS-REQUEST.XML SEND-SMS-RESPONSE.XML <sms:SendSmsResponse xmlns:sms="http://www.smsgateway.org/schema/SmsGateway/v1">
 <sms:communicationId>${communicationId}</sms:communicationId>
 <sms:success>true</sms:success>
 <sms:statusCode>200</sms:statusCode>
 <sms:statusMsg>OK</sms:statusMsg>
 </sms:SendSmsResponse>
  27. ENDPOINTS ENDPOINTS Component Description citrus-http Http REST client and server

    citrus-jms JMS queue or topic destination citrus-ws SOAP client and server citrus-mail SMTP mail client and server citrus-docker Docker container management citrus-camel Apache Camel endpoint citrus-ftp FTP client and server citrus-vertx Vert.x endpoint citrus-ssh SSH client and server …
  28. CITRUS SUMMARY ▸ Citrus makes it easy to test messaging

    ▸ Simulate messaging interfaces on client and server ▸ Citrus Arquillian extension ▸ @CitrusResource, @CitrusEndpoint, @CitrusFramework ▸ Runs via command line or Java IDE