+ All Categories
Home > Documents > Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... ·...

Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... ·...

Date post: 21-May-2020
Category:
Upload: others
View: 5 times
Download: 0 times
Share this document with a friend
569
Transcript
Page 1: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to
Page 2: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

0

1

2

3

4

5

6

7

8

9

10

10.1

10.2

10.3

10.4

10.5

10.6

10.7

11

12

13

13.1

13.2

13.3

13.4

13.5

13.6

TableofContentsIntroduction

Preface

Changesnew

Introduction

Setup

Testcase

Testvariables

Run

Configuration

Endpoints

Validation

Xml

Schema

Json

Xhtml

Plaintext

Binary

Gzip

Xpath

JsonPath

Actions

Send

Receive

Database

Sleep

Java

Timeout

CitrusReferenceGuide

2

Page 3: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

13.7

13.8

13.9

13.10

13.11

13.12

13.13

13.14

13.15

13.16

13.17

13.18

13.19

13.20

13.21

13.22

13.23

13.24

13.25

14

15

16

16.1

16.2

16.3

16.4

16.5

16.6

16.7

16.8

Echo

Stoptime

Createvariables

Trace

Transform

Groovy

Fail

Input

Load

Wait

PurgeJMSqueues

Purgechannels

Purgeendpoints

Assert

Catch

Antrun

Manageserver

Stoptimer

Genericaction

Templates

Testbehaviors

Containers

Sequential

Conditional

Parallel

Iterate

Repeat

RepeatOnError

Timer

Custom

CitrusReferenceGuide

3

Page 4: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

Finally

Jms

Http

HttpWebsockets

Soap

Ftp

Messagechannel

File

Camel

Vertx

Mail

Arquillian

Docker

Kubernetes

Ssh

Rmi

Jmx

Cucumber

Zookeeper

Restdocs

Selenium

Endpointcomponent

Endpointadapter

Functions

ValidationMatchers

Datadictionary

Testactors

Testsuite

Metainfo

Messagetracing

CitrusReferenceGuide

4

Page 5: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

47

48

48.1

49

49.1

49.2

49.3

49.4

49.5

49.6

49.7

49.8

49.9

49.10

Reporting

Samples

FlightBookingSample

Appendix

Changes2.6

Changes2.5

Changes2.4

Changes2.3

Changes2.2

Changes2.1

Changes2.0

Changes1.4

Changes1.3

Changes1.2

CitrusReferenceGuide

5

Page 6: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

CitrusFramework-ReferenceDocumentation

AuthorsChristophDeppisch,MartinMaher

Version2.7.1

Copyright©2017ConSolSoftwareGmbH

www.citrusframework.org

CitrusReferenceGuide

6Introduction

Page 7: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Preface

Integrationtestingcanbeveryhard,especiallywhenthereisnosufficienttoolsupport.UnittestingisflavoredwithfantastictoolsandAPIslikeJUnit,TestNG,EasyMock,Mockitoandsoon.Thesetoolssupportyouinwritingautomatedtests.Atesterwhoisinchargeofintegrationtestingmaylackoftoolsupportforautomatedtestingespeciallywhenitcomestosimulatemessaginginterfaces.

Inatypicalenterpriseapplicationscenariothetestteamhastodealwithdifferentmessaginginterfacesandvarioustransportprotocols.Withoutsufficienttoolsupporttheautomatedintegrationtestingofmessage-basedinteractionsbetweeninterfacepartnersisexhaustingandsometimesbarelypossible.

Thetesterisforcedtosimulateseveralinterfacepartnersinanend-to-endintegrationtest.Thefirstthingthatcomestoourmindismanualtesting.Nodoubtmanualtestingisfast.Inlongtermperspectivemanualtestingistimeconsumingandcausessevereproblemsregardingmaintainabilityastheyareerrorproneandnotrepeatable.

TheCitrusframeworkgivesacompletetestautomationtoolforintegrationtestingofenterpriseapplications.Youcantestyourmessageinterfacestootherapplicationsasclientandserver.EverytimeacodechangeappliesallautomatedCitrustestsensurethestabilityofinterfacesandmessagecommunication.

RegressiontestingandcontinuousintegrationisveryeasyasCitrusfitsintoyourbuildlifecylceasusualJavaunittest.YoucanuseCitruswithJUnitorTestNGinordertointegratewithyourapplicationbuild.

WithpowerfulvalidationcapabilitiesforvariousmessageformatslikeXML,CSVorJSONCitrusisdesignedtoprovidefullyautomatedintegrationtestsforend-to-endusecases.Citruseffectivelycomposescomplexmessagingusecaseswithresponsegeneration,errorsimulation,databaseinteractionandmore.

ThisdocumentationprovidesareferenceguidetoallfeaturesoftheCitrustestframework.Itgivesadetailedpictureofeffectiveintegrationtestingwithautomatedintegrationtestenvironments.Sincethisdocumentisconsideredtobeunderconstruction,pleasedonothesitatetogiveanycommentsorrequeststoususingouruserorsupportmailinglists.

CitrusReferenceGuide

7Preface

Page 8: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

What'snewinCitrus2.7?!Citrus2.7isusingJava8!TheCitrussourcesarecompiledwithJava8whichmeansthatfromnowonyouneedatleastJava8runtimetoworkwithCitrus.WiththisJava8baseCitrusisproudtowelcometwonewcrewmembersforsupportingSeleniumandKubernetesintests.Notenoughwehavethefollowingfeaturesincludedinthebox.

Java8

CitrusisnowusingJava8.ThisismainlybecauseweneedtomoveoninusinglatestversionsofSpringFramework,ApacheCamelandsoon.IfyouarestillstuckonJava7youcannotupdateto2.7astheCitrussourcesarecompiledwithJava8.PleasecontactusincaseyoureallycannotupdatetoJava8inyourproject.WecanthinkofaminorbugfixversionwithCitrus2.6basethatstillsupportsJava7runtime.OnthebrightsidewecannowusethefullpowerofLambdaexpressionsandotherJava8featuresinCitruscodebase.

Kubernetessupport

CitrusisnowabletointeractwithKubernetesremoteAPIinordertomanagepods,servicesandotherresourcesontheKubernetesplatform.TheKubernetesclientisbasedontheFabric8JavaclientthatinteractswiththeKubernetesAPIviaRESTservices.SoyoucanaccessKubernetesresourceswithinCitrusinordertochangeorvalidatetheresourcestateforcontainerizedtesting.Thisisveryusefulwhendealingwithcontainerapplicationenvironmentsaspartoftheintegrationtests.PleasestaytunedforblogpostsandtutorialsamplesonhowCitruscanhelpyoutestMicroserviceswithDockerandKubernetes.Thebasicusageisdescribedinsectionkubernetes.

Seleniumsupport

UserinterfaceandbrowsertestinghasnotbeenafocuswithinCitrusintegrationtestinguntilnowthatwecanintegratewiththefamousSeleniumUItestinglibrary.Thankstothegreatcontributionsmadebythecommunity-especiallybyvdsrd@github-wecanuseSeleniumbasedactionsandfeaturesdirectlyinaCitrustestcase.TheCitrusJavaandXMLDSLbothprovidecomfortableaccesstotheSeleniumAPIinordertosimulate

CitrusReferenceGuide

8Changesnew

Page 9: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

userinteractionwithinabrowser.ThemixofuserbasedactionsandCitrusmessagingtransportsimulationgivescompletenewwaysofhandlingcomplexintegrationscenarios.ReadmoreaboutthisinchapterSelenium.

Environmentbasedbefore/aftersuite

Youcanenable/disablebeforeandaftersuiteactionsbasedonoptionalenvironmentorsystemproperties.Userscangivepropertynamesorpropertyvaluesthatarecheckedbeforeexecution.Onlyincasetheenvironmentpropertychecksdopasstheactionsareexecutedbefore/afterthetestsuiterun.

WsAddressingheadercustomization

WehaveimprovedtheheadercustomizationoptionswhenusingSOAPWSAddressingfeature.YoucannowoverwritethedefaultWSAddressingheaderspertestactioninadditiontodefiningtheheadersonclientendpointcomponentlevel.

JsonPathdatadictionary

Jsondatadictionarywasbasedonasimpledotnotatedsyntax.NowyoucanalsousemorecomplexJsonPathexpressionsinordertooverwriteelementsinJsonmessagesbasedonthedatadictionarysettingsinCitrus.Readmoreaboutthatinchapterdata-dictionary.

JavaDSLtestbehavior

TestbehaviorsinJavaDSLrepresenttemplatesinXMLDSL.ThebehaviorencapsulatesasetoftestactionstoagroupthatcanbeappliedtomultipleJavaDSLtests.ThisenablesyoutocombinecommontestactionsinJavaDSLwithmorecomfortablereuseoftestactiondefinitions.Seechaptertest-behaviorshowtousethat.

Autoselectmessagetype

DefaultmessagetypeforvalidationtasksinCitrushasbeenXML.BasedonthismessagetypetherespectivemessagevalidatorimplementationappliesforXML,JSON,plaintextandsoon.Youcannowchangethisdefaultmessagetypebysettingasystemproperty(citrus.default.message.type).AlsoCitrusimprovedtheautoselectalgorithmwhenthedefaultmessagetypeisobviouslynotapplicable.WhenamessagearrivesinCitrusthereceivingactiontriestofindoutwhichmessagevalidatorfitsbestaccordingto

CitrusReferenceGuide

9Changesnew

Page 10: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

themessagepayload.XMLmessagecontentisautomaticallyidentifiedby<>characters.JSONmessagepayloadsareidentifiedbyor[]charactersforobjectsandarrayrepresentations.ThiswayCitrustriestofindthebestmatchingmessagevalidatorfortheincomingmessage.BeforethatCitrushasalwaysbeenusingthedefaultmessagetypeXML.

Readaboutdifferentmessagevalidatorsinvalidation.

DefaultCucumbersteps

TheCitrusCucumberextensionnowdefinesdefaultstepdefinitionsforHttp,DockerandSelenium.ThesedefaultstepsarereadyforusageinanyCucumberCitrusfeaturespecification.YoucanloadthedefaultstepsasadditionalgluepackagesinyourCucumberoptions.Afterthatyouarereadytogoforusingthedefaultstepsdirectlyinfeaturespecificationfiles.WiththeextensionsyoucanperformDockerandSeleniumcommandsveryeasy.AlsoyoucandescribetheHttpRESTclient-servercommunicationinBDDstyle.Readmoreaboutthisincucumber.

Refactoring

DeprecatedAPIsandclassesthatcoexistedalongtimearenowremoved.Ifyourprojectisusingonofthesedeprecatedclassesyoumayrunintocompiletimeerrors.PleasehavealookattheCitrusAPIJavaDocsanddocumentationinordertofindouthowtousethenewAPIsandclassesthatreplacedtheolddeprecatedstuff.

Bugfixes

Bugsarepartofoursoftwaredevelopersworldandfixingthemispartofyourdailybusiness,too.FindingandsolvingissuesmakesCitrusbettereveryday.ForadetailedlistingofallbugfixespleaserefertothecompletechangeslogofeachreleaseinJIRA(http://www.citrusframework.org/changes-report.html).

CitrusReferenceGuide

10Changesnew

Page 11: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

IntroductionNowadaysenterpriseapplicationsusuallycommunicatewithdifferentpartnersoverlooselycoupledmessaginginterfaces.Theinteractionandtheinterfacecontractneedstobetestedinintegrationtesting.

Inatypicalintegrationtestscenarioweneedtosimulatethecommunicationpartnersovervarioustransports.Howcanwetestusecasescenariosthatincludeseveralinterfacepartnersinteractingwitheachother?Howcansomebodyensurethatthesoftwarecomponentsworkcorrectlyregardingtheinterfacecontract?Howcansomebodyrunintegrationtestcasesinanautomatedreproducibleway?Citrustriestoanswerthesequestions!

Overview

Citrusaimstostronglysupportyouinsimulatinginterfacepartnersacrossdifferentmessagingtransports.YoucaneasilyproduceandconsumemessageswithawiderangeofprotocolslikeHTTP,JMS,TCP/IP,FTP,SMTPandmore.Theframeworkisabletobothactasaclientandserver.IneachcommunicationstepCitrusisabletovalidatemessagecontentstowardssyntaxandsemantics.

InadditiontothattheCitrusoffersawiderangeoftestactionstotakecontroloftheprocessflowduringatest(e.g.iterations,systemavailabilitychecks,databaseconnectivity,parallelism,delaying,errorsimulation,scriptingandmanymore).

ThebasicgoalinCitrustestcasesistodescribeawholeusecasescenarioincludingseveralinterfacepartnersthatexchangemanymessageswitheachother.ThecompositionofcomplexmessageflowsinasingletestcasewithseveralteststepsisoneofthemajorfeaturesinCitrus.

ThetestcasedescriptioniseitherdoneinXMLorJavaandcanbeexecutedmultipletimesasautomatedintegrationtest.WithJUnitandTestNGintegrationCitruscaneasilybeintegratedintoyourbuildlifecycleprocess.DuringatestCitrussimulatesallsurroundinginterfacepartners(clientorserver)withoutanycodingeffort.Witheasydefinitionofexpectedmessagecontent(headerandpayload)forXML,CSV,SOAP,JSONorplaintextmessagesCitrusisabletovalidatetheincomingdatatowardssyntaxandsemantics.

CitrusReferenceGuide

11Introduction

Page 12: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Usagescenarios

IfyouareinchargeofanenterpriseapplicationinamessagebasedsolutionwithmessageinterfacestoothersoftwarecomponentsyoushoulduseCitrus.IncaseyourprojectinteractswithothersoftwareoverdifferentmessagingtransportsandincaseyouneedtosimulatetheseinterfacepartnersonclientorserversideyoushoulduseCitrus.Incaseyouneedtocontinuouslycheckthesoftwarestabilitynotonlyonaunittestingbasisbutalsoinanend-to-endintegrationscenarioyoushoulduseCitrus.Bugfixing,releaseorregressiontestingisveryeasywithCitrus.IncaseyouarestrugglingwithcodestabilityandfeeluncomfortableregardingyournextsoftwarereleaseyoushoulddefinitelyuseCitrus.

ThistestsetupistypicalforaCitrususecase.Insuchatestscenariowehaveasystemundertest(SUT)withseveralmessageinterfacestootherapplicationslikeyouwouldhavewithanenterpriseservicebusforinstance.AclientapplicationinvokesservicesontheSUTapplication.TheSUTislinkedtoseveralbackendapplicationsovervariousmessagingtransports(hereSOAP,JMS,andHttp).Interimmessagenotificationsandfinalresponsesaresentbacktotheclientapplication.Thisgeneratesabunchofmessagesthatareexchangedthroughouttheapplicationsinvolved.

IntheautomatedintegrationtestCitrusneedstosendandreceivethosemessagesoverdifferenttransports.Citrustakescareofallinterfacepartners(ClientApplication,Backend1,Backend2,Backend3)andsimulatestheirbehaviorbysendingproperresponsemessagesinordertokeepthemessageflowalive.

Eachcommunicationstepcomeswithmessagevalidationandcomparisonagainstanexpectedmessagetemplate(e.g.XMLorJSONdata).BesidesmessagingactionsCitrusisalsoabletoperformarbitraryothertestactions.Citrusisabletoperformadatabasequerybetweenrequestsasanexample.

CitrusReferenceGuide

12Introduction

Page 13: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TheCitrustestcaserunsfullyautomatedasaJavaapplication.InfactaCitrustestcaseisnothingbutaJUnitorTestNGtestcase.Stepbystepthewholeusecasescenarioisperformedlikeinarealproductionenvironment.TheCitrustestisrepeatableandisincludedintothesoftwarebuildprocess(e.g.usingMavenorANT)likeanormalunittestcasewoulddo.Thisgivesyoufullyautomatedintegrationteststoensureinterfacestability.

ThefollowingreferenceguidewalksthroughallCitruscapabilitiesandshowshowtosetupagreatintegrationtestwithCitrus.

CitrusReferenceGuide

13Introduction

Page 14: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

SetupThischapterdiscusseshowtogetstartedwithCitrus.Itdealswiththeinstallationandsetupoftheframework,soyouarereadytostartwritingtestcasesafterreadingthischapter.

UsuallyyouwoulduseCitrusasadependencylibraryinyourproject.InMavenyouwouldjustaddCitrusasatest-scopeddependencyinyourPOM.WhenusingANTyoucanalsorunCitrusasnormalJavaapplicationfromyourbuild.xml.AsCitrustestsarenothingbutnormalunittestsyoucouldalsouseJUnitorTestNGanttaskstoexecutetheCitrustestcases.

ThischapterdescribestheCitrusprojectsetuppossibilities,chooseoneofthemthatfitsbesttoincludeCitrusintoyourproject.

UsingMaven

Citrususeshttp://maven.apache.org/internallyasaprojectbuildtoolandprovidesextendedsupportforMavenprojects.Mavenwilleaseupyourlifeasitmanagesprojectdependenciesandprovidesextendedbuildlifecyclesandconventionsforcompiling,testing,packagingandinstallingyourJavaproject.ThereforeitisrecommendedtousetheCitrusMavenprojectsetup.IncaseyoualreadyuseMavenitismostsuitableforyoutoincludeCitrusasatest-scopeddependency.

AsMavenhandlesallprojectdependenciesautomaticallyyoudonotneedtodownloadanyCitrusprojectartifactsinadvance.IfyouarenewtoMavenpleaserefertotheofficialMavendocumentationtofindouthowtosetupaMavenproject.

UseCitrusMavenarchetype

IfyoustartfromscratchorincaseyouwouldliketohaveCitrusoperatinginaseparateMavenmoduleyoucanusetheCitrusMavenarchetypetocreateanewMavenproject.ThearchetypewillsetupabasicCitrusprojectstructurewithbasicsettingsandfiles.

mvnarchetype:generate-DarchetypeCatalog=http://citrusframework.org

Choosearchetype:1:http://citrusframework.org->citrus-archetype(BasicarchetypeforCitrusintegrationtestproject)Chooseanumber:1

CitrusReferenceGuide

14Setup

Page 15: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

DefinevalueforgroupId:com.consol.citrus.samplesDefinevalueforartifactId:citrus-sampleDefinevalueforversion:1.0-SNAPSHOTDefinevalueforpackage:com.consol.citrus.samples

InthesampleaboveweusedtheCitrusarchetypecataloglocatedontheCitrushomepage.CitrusarchetypesarealsoavailableinMavencentralrepository.Socanalsojustuse"mvnarchetype:generate".AsthelistofdefaultarchetypesavailableinMavencentralisverylongyoumightwanttofilterthelistwith"citrus"andyouwillgetjustafewpossibilitiestochoosefrom.

Weloadthearchetypeinformationfrom"http://citrusframework.org"andchoosetheCitrusbasicarchetype.Nowyouhavetodefineseveralvaluesforyourproject:thegroupId,theartifactId,thepackageandtheprojectversion.Afterthatwearedone!MavencreatedaCitrusprojectstructureforuswhichisreadyfortesting.Youshouldseethefollowingbasicprojectfolderstructure.

citrus-sample|+src||+main|||+java|||+resources||+citrus|||+java|||+resources|||+testspom.xml

TheCitrusprojectisabsolutelyreadyfortesting.WithMavenwecanbuild,package,installandtestourprojectrightawaywithoutanyadjustments.Trytoexecutethefollowingcommands:

mvnintegration-testmvnintegration-test-Dtest=MyFirstCitrusTest

NoteIfyouneedadditionalassistanceinsettingupaCitrusMavenprojectpleasevisitourMavensetuptutorialonhttp://www.citrusframework.org/tutorials.html.

AddCitrustoexistingMavenproject

CitrusReferenceGuide

15Setup

Page 16: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

IncaseyoualreadyhaveaproperMavenprojectyoucanalsointegrateCitruswithit.JustaddtheCitrusprojectdependenciesinyourMavenpom.xmlasadependencylikefollows.

WeaddCitrusastest-scopedprojectdependencytotheprojectPOM(pom.xml)

<dependency><groupId>com.consol.citrus</groupId><artifactId>citrus-core</artifactId><version>2.7.1</version><scope>test</scope></dependency>

IncaseyouwouldliketousetheCitrusJavaDSLalsoaddthisdependencytotheproject

<dependency><groupId>com.consol.citrus</groupId><artifactId>citrus-java-dsl</artifactId><version>2.7.1</version><scope>test</scope></dependency>

AddthecitrusMavenplugintoyourproject

<plugin><groupId>com.consol.citrus.mvn</groupId><artifactId>citrus-maven-plugin</artifactId><version>2.7.1</version><configuration><author>DonaldDuck</author><targetPackage>com.consol.citrus</targetPackage></configuration></plugin>

NowthatwehaveaddedCitrustoourMavenprojectwecanstartwritingnewtestcaseswiththeCitrusMavenplugin:

mvncitrus:create-test

OnceyouhavewrittentheCitrustestcasesyoucanexecutethemautomaticallyinyourMavensoftwarebuildlifecylce.Thetestswillbeincludedintoyourprojectsintegration-testphaseusingtheMavensurefireplugin.Hereisasamplesurefireconfigurationfor

CitrusReferenceGuide

16Setup

Page 17: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Citrus.

<plugin><artifactId>maven-surefire-plugin</artifactId><version>2.4.3</version><configuration><skip>true</skip></configuration><executions><execution><id>citrus-tests</id><phase>integration-test</phase><goals><goal>test</goal></goals><configuration><skip>false</skip></configuration></execution></executions></plugin>

TheCitrussourcedirectoriesaredefinedastestsourceslikefollows:

<testSourceDirectory>src/it/java</testSourceDirectory><testResources><testResource><directory>src/it/java</directory><includes><include>**</include></includes><excludes><exclude>*.java</exclude></excludes></testResource><testResource><directory>src/it/tests</directory><includes><include>**/*</include></includes><excludes></excludes></testResource></testResources>

NoweverythingissetupandyoucancalltheusualMaveninstallgoal(mvncleaninstall)inordertobuildyourproject.TheCitrusintegrationtestsareexecutedautomaticallyduringthebuildprocess.BesidesthatyoucancalltheMavenintegration-

CitrusReferenceGuide

17Setup

Page 18: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

testphaseexplicitlytoexecuteallCitrustestsoraspecifictestbyitsname:

mvnintegration-testmvnintegration-test-Dtest=MyFirstCitrusTest

NoteIfyouneedadditionalassistanceinsettingupaCitrusMavenprojectpleasevisitourMavensetuptutorialonhttp://www.citrusframework.org/tutorials.html.

UsingAnt

Antisaverypopularwaytocompile,test,packageandexecuteJavaprojects.TheApacheprojecthaseffectivelybecomeastandardinbuildingJavaprojects.YoucanrunCitrustestcaseswithAntasCitrusisnothingbutaJavaapplication.ThissectiondescribesthestepstosetupaproperCitrusAntproject.

Preconditions

BeforewestartwiththeCitrussetupbesuretomeetthefollowingpreconditions.Thefollowingsoftwareshouldbeinstalledonyourcomputer,inordertousetheCitrusframework:

Java8orhigher

InstalledJDKplusJAVA_HOMEenvironmentvariablesetupandpointingtoyourJavainstallationdirectory

JavaIDE(optional)

AJavaIDEwillhelpyoutomanageyourCitrusproject(e.g.creatingandexecutingtestcases).YoucanusetheanyJavaIDE(e.g.EclipseorIntelliJIDEA)butalsoanyconvenientXMLEditortowritenewtestcases.

Ant1.8orhigher

Ant(http://ant.apache.org/)willruntestsandcompileyourCitruscodeextensionsifnecessary.

Download

FirstofallweneedtodownloadthelatestCitrusreleasearchivefromtheofficialwebsitehttp://www.citrusframework.org

CitrusReferenceGuide

18Setup

Page 19: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Citruscomestoyouasazippedarchiveinoneofthefollowingpackages:

citrus-x.x-releasecitrus-x.x-src

ThereleasepackageincludestheCitrusbinariesaswellasthereferencedocumentationandsomesampleapplications.

IncaseyouwanttogetintouchwithdevelopinganddebuggingCitrusyoucanalsogowiththesourcearchivewhichgivesyouthecompleteCitrusJavacodesources.ThewholeCitrusprojectisalsoaccessibleforyouonhttp://github.com/christophd/citrus.ThisopengitrepositoryonGitHubenablesyoutobuildCitrusfromscratchwithMavenandcontributecodechanges.

Installation

AfterdownloadingtheCitrusarchivesweextractthoseintoanappropriatelocationonthelocalstorage.WeareseekingfortheCitrusprojectartifactscomingasnormalJavaarchives(e.g.citrus-core.jar,citrus-ws.jar,etc.)

YouhavetoincludethoseCitrusJavaarchivesaswellasalldependencylibrariestoyourApacheAntJavaclasspath.Usuallyyouwouldcopyalllibrariesintoyourproject'slibdirectoryanddeclarethoselibrariesintheAntbuildfile.AsthisapproachcanbeverytimeconsumingIrecommendtouseadependencymanagementAPIsuchasApacheIvywhichgivesyouautomaticdependencyresolutionlikethatfromMaven.Inparticularthiscomesinhandywithallthe3rdpartydependenciesthatwouldberesolvedautomatically.

NomatterwhatapproachyouareusingtosetuptheApacheAntclasspathseethefollowingsampleAntbuildscriptwhichusestheCitrusprojectartifactsincombinationwiththeTestNGAnttaskstorunthetests.

<projectname="citrus-sample"basedir="."default="citrus.run.tests"xmlns:artifact="antlib:org.apache.maven.artifact.ant"

<propertyfile="src/it/resources/citrus.properties"/>

<pathid="maven-ant-tasks.classpath"path="lib/maven-ant-tasks-2.1.3.jar"/><typedefresource="org/apache/maven/artifact/ant/antlib.xml"uri="antlib:org.apache.maven.artifact.ant"classpathref="maven-ant-tasks.classpath"/>

<artifact:pomid="citrus-pom"file="pom.xml"/><artifact:dependenciesfilesetId="citrus-dependencies"pomRefId="citrus-pom"/>

CitrusReferenceGuide

19Setup

Page 20: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<pathid="citrus-classpath"><pathelementpath="src/it/java"/><pathelementpath="src/it/resources"/><pathelementpath="src/it/tests"/><filesetrefid="citrus-dependencies"/></path>

<taskdefresource="testngtasks"classpath="lib/testng-6.8.8.jar"/>

<targetname="compile.tests"><javacsrcdir="src/it/java"classpathref="citrus-classpath"/><javacsrcdir="src/it/tests"classpathref="citrus-classpath"/></target>

<targetname="create.test"description="Createsanewemptytestcase"><inputmessage="Entertestname:"addproperty="test.name"/><inputmessage="Entertestdescription:"addproperty="test.description"/><inputmessage="Enterauthor'sname:"addproperty="test.author"defaultvalue="$default.test.author"<inputmessage="Enterpackage:"addproperty="test.package"defaultvalue="$default.test.package"<inputmessage="Enterframework:"addproperty="test.framework"defaultvalue="testng"/>

<javaclassname="com.consol.citrus.util.TestCaseCreator"><classpathrefid="citrus-classpath"/><argline="-name$test.name-author$test.author-description$test.description-package$test.package-framework$test.framework"</java></target>

<targetname="citrus.run.tests"depends="compile.tests"description="RunsallCitrustests"<testngclasspathref="citrus-classpath"><classfilesetdir="src/it/java"includes="**/*.class"/></testng></target>

<targetname="citrus.run.single.test"depends="compile.tests"description="Runsasingletestbyname"<touchfile="test.history"/><loadpropertiessrcfile="test.history"/>

<echomessage="Lasttestexecuted:$last.test.executed"/><inputmessage="Entertestnameorleaveemptyforlasttestexecuted:"addproperty="testclass"

<propertyfilefile="test.history"><entrykey="last.test.executed"type="string"value="$testclass"/></propertyfile>

<testngclasspathref="citrus-classpath"><classfilesetdir="src/it/java"includes="**/$testclass.class"/></testng></target>

</project>

CitrusReferenceGuide

20Setup

Page 21: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

NoteIfyouneeddetailedassistanceforbuildingCitruswithAntdoalsovisitourtutorialssectiononhttp://www.citrusframework.org.ThereyoucanfindatutorialwhichdescribestheCitrusJavaprojectsetupwithAntfromscratch.

CitrusReferenceGuide

21Setup

Page 22: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TestcasesNowletusstartwritingtestcases!AtestcaseinCitrusdescribesallstepsforacertainusecaseinonesinglefile.TheCitrustestholdsasequenceoftestactions.Eachactionrepresentsaveryspecialpurposesuchassendingorreceivingamessage.Typicallywithmessage-basedenterpriseapplicationsthesendingandreceivingofmessagesrepresentthemainactionsinsideatest.

HoweveryouwilllearnthatCitrusismorethanjustasimpleSOAPclientforinstance.Eachtestcasecanholdcomplexactionssuchasconnectingtothedatabase,transformingdata,addingloopsandconditionalsteps.WiththedefaultCitrusactionsetyoucanaccomplishverycomplexusecaseintegrationtests.Laterinthisguidewewillbrieflydiscussallavailabletestactionsandlearnhowtousevariousmessagetransportswithinthetest.Fornowwewillconcentrateonthebasictestcasestructure.

ThefigureabovedescribesatypicaltestactionsequenceinCitrus.Alistofsendingandreceivingtestactionscomposingatypicaltestcasehere.EachactionreferencesapredefinedCitrusendpointcomponentthatwearegoingtotalkaboutlateron.

Sohowdowedefinethosetestcases?IngeneralCitrusspecifiestestcasesasJavaclasses.WithTestNGorJUnityoucanexecutetheCitrustestswithinyourJavaruntimeasyouwoulddowithinunittesting.YoucancodetheCitrustestinasingleJavaclass

CitrusReferenceGuide

22Testcase

Page 23: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

doingassertionsandusingSpring'sdependencyinjectionmechanisms.

IfyouarenotfamiliartowritingJavacodeyoucanalsowriteCitrustestsasXMLfiles.WhatevertestlanguageyouchooseforCitrusthewholetestcasedescriptiontakesplaceinonesinglefile(JavaorXML).ThischapterwillintroducethecustomXMLschemalanguageaswellastheJavadomainspecificlanguagesoyouwillbeabletowriteCitrustestcasesnomatterwhatknowledgebaseyoubelongto.

WritingtestcasesinXML

Putsimply,aCitrustestcaseisnothingbutasimpleSpringXMLconfigurationfile.TheSpringframeworkhasbecomeastateoftheartdevelopmentframeworkforenterpriseJavaapplications.AsyouworkwithCitrusyouwillalsolearnhowtousetheSpringIoc(Inversionofcontrol)containerandtheconceptsofdependencyinjection.SoletushavealookatthepureSpringXMLconfigurationsyntaxfirst.YouarefreetowritefullycompatibletestcasesfortheCitrusframeworkjustusingthissyntax.

Springbeandefinitionsyntax

<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd">

<beanname="MyFirstTest"class="com.consol.citrus.TestCase"><propertyname="variableDefinitions"><!--variablesofthistestgohere--></property><propertyname="actions"><!--actionsofthistestgohere--></property></bean></beans>

CitruscanexecutetheseSpringbeandefinitionsasnormaltestcases-noproblem,butthepureSpringXMLsyntaxisveryverboseandprobablynotthebestwaytodescribeatestcaseinCitrus.InparticularyouhavetoknowalotofCitrusinternalssuchasJavaclassnamesandpropertynames.Inadditiontothatastestscenariosgetmorecomplexthetestcasesgrowinsize.Soweneedamoreeffectiveandcomfortablewayofwritingtests.ThereforeCitrusprovidesacustomXMLschemadefinitionforwritingtestcaseswhichismuchmoreadequateforourtestingpurpose.

CitrusReferenceGuide

23Testcase

Page 24: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ThecustomXMLschemaaimstoreachtheconvenienceofdomainspecificlanguages(DSL).LetushavealookattheCitrustestdescribingXMLlanguagebyintroducingafirstverysimpletestcasedefinition:

XMLDSL

<spring:beansxmlns="http://www.citrusframework.org/schema/testcase"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:spring="http://www.springframework.org/schema/beans"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/testcasehttp://www.citrusframework.org/schema/testcase/citrus-testcase.xsd">

<testcasename="MyFirstTest"><description>Firstexampleshowingthebasictestcasedefinitionelements!</description><variables><variablename="text"value="HelloTestFramework"/></variables><actions><echo><message>$text</message></echo></actions></testcase></spring:beans>

Wedoneedthe<spring:beans>rootelementastheXMLfileisreadbytheSpringIoCcontainer.InsidethisrootelementtheCitrusspecificnamespacedefinitionstakeplace.

Thetestcaseitselfgetsamandatorynamethatmustbeuniquethroughoutalltestcasesinaproject.Youwillreceiveerrorswhenusingduplicatetestnames.ThetestnamehastofollowthecommonJavanamingconventionsandrulesforJavaclasses.Thismeansnamesmustnotcontainanywhitespacecharactersbutcharacterslike'-','.','_'aresupported.Forexample,TestFeature_1isvalidbutTestFeature1isnotasitcontainswhitespacecharacterslikespaces.

NowthatwehaveanXMLdefinitionthatdescribesthestepsofourtestweneedaJavaexecutableforthetest.TheJavaexecutableisneededfortheframeworkinordertorunthetest.SeethefollowingsampleJavaclassthatrepresentsasimpleCitrusJavatest:

importorg.testng.annotations.Test;

CitrusReferenceGuide

24Testcase

Page 25: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

importcom.consol.citrus.annotations.CitrusTest;importcom.consol.citrus.testng.AbstractTestNGCitrusTest;

@TestpublicclassMyFirstTestextendsAbstractTestNGCitrusTest

@CitrusXmlTest(name="MyFirstTest")publicvoidmyFirstTest()

ThesampleaboveisaJavaclassthatrepresentsavalidCitrusJavaexecutable.TheJavaclasshasnoprogramminglogicasweuseaXMLtestcasehere.TheJavaclasscanalsobegeneratedusingtheCitrusMavenplugin.TheJavaclassextendsfrombasicsuperclassAbstractTestNGCitrusTestandthereforeusesTestNGasunittestframework.CitrusalsosupportsJUnitasunittestframework.Readmoreaboutthisinrun-testngandrun-junit.

UptonowitisimportanttounderstandthatCitrusalwaysneedsaJavaexecutabletestclass.IncaseweusetheXMLtestrepresentationtheJavapartisgeneric,canbegeneratedandcontainsnoprogramminglogic.TheXMLtestdefinesallstepsandisourprimarytestcasedefinition.

WritingtestcasesinJava

BeforewegointomoredetailsontheattributesandactionsthattakeplacewithinatestcasewejusthavealookathowtowritetestcaseswithpureJavacode.CitrusworkswithJavaandusesthewellknownJUnitandTestNGframeworkbenefitsthatyoumaybeusedtoasatester.ManyusersmayprefertowriteJavacodeinsteadoftheverboseXMLsyntax.ThereforeyouhaveanotherpossibilityforwritingCitrustestsinpureJava.

WhenusingtheCitrusJavaDSLweneedtoincludeaspecialMavendependencymoduletoourprojectthatprovidestheneededAPI.

<dependency><groupId>com.consol.citrus</groupId><artifactId>citrus-java-dsl</artifactId><version>2.7.1</version><scope>test</scope></dependency>

CitrusingeneraldifferencesbetweentwowaysoftestcasesinJava.Thesearetest-designersandtest-runnersthatwedealwitheachinthenexttwosections.

CitrusReferenceGuide

25Testcase

Page 26: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

JavaDSLtestdesigner

ThefirstwayofdefiningaCitrustestinJavaisthetest-designer.TheJavaDSLforatestdesignerworkssimilartotheXMLapproach.Thewholetestcaseisbuiltwithalltestactionsfirst.ThenthewholetestcaseisexecutedasawholeCitrustest.ThisishowtodefineaCitrustestwithdesignerJavaDSLmethods:

JavaDSLdesigner

importorg.testng.annotations.Test;importcom.consol.citrus.annotations.CitrusTest;importcom.consol.citrus.dsl.testng.TestNGCitrusTestDesigner;

@TestpublicclassMyFirstTestDesignerextendsTestNGCitrusTestDesigner@CitrusTest(name="MyFirstTest")publicvoidmyFirstTest()description("Firstexampleshowingthebasictestcasedefinitionelements!");

variable("text","HelloTestFramework");

echo("$text");

CitrusprovidesabaseJavaclasscom.consol.citrus.dsl.testng.TestNGCitrusTestDesignerthatprovidesallcapabilitiesforyouinformofbuilderpatternmethods.Justusethe@CitrusTestannotationontopofthetestmethod.Citruswillusethemethodnameasthetestnamebydefault.Asyoucanseeintheexampleaboveyoucanalsocustomizethetestnamewithinthe@CitrusTestannotation.Thetestmethodbuildsalltestactionsusingthetestbuilderpattern.Thedefinedtestactionswillthenbecalledlateronduringtestruntime.

Thedesigntimeruntimedifferenceintest-designerisreallyimportanttobeunderstood.YoucanmixtheCitrusJavaDSLexecutionwithotherJavacodewithcertainlimitations.Wewillexplainthislateronwhenintroducingthetest-runner.

ThisisthebasictestJavaclasspatternusedinCitrus.Youasatesterwithdevelopmentbackgroundcaneasilyextendthispatternforcustomizedlogic.AgainifyouarecomingwithoutcodingexperiencedonotworrythisJavacodeisoptional.YoucandoexactlythesamewiththeXMLsyntaxonlyasshownbefore.ThetestdesignerJavaDSLismuchmorepowerfulthoughasyoucanusethefullJavaprogramminglanguagewithclassinheritanceandmethoddelegation.

CitrusReferenceGuide

26Testcase

Page 27: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Wehavementionedthatthetest-designerwillbuildthecompletetestcaseindesigntimewithallactionsfirstbeforeexecutionofthewholetestcasetakesplaceatruntimeofthetest.ThisapproachhastheadvantagethatCitrusknowsalltestactionsinatestbeforeexecution.OntheotherhandyouarelimitedinmixingJavaDSLmethodcallsandnormalJavacode.Thefollowingexampleshouldclarifythingsalittlebit.

JavaDSLdesigner

importorg.testng.annotations.Test;importcom.consol.citrus.annotations.CitrusTest;importcom.consol.citrus.dsl.testng.TestNGCitrusTestDesigner;

@TestpublicclassLoggingTestDesignerextendsTestNGCitrusTestDesignerprivateLoggingServiceloggingService=newLoggingService();

@CitrusTest(name="LoggingTest")publicvoidloggingTest()echo("BeforeloggingServicecall");

loggingService.log("Nowcalledcustomloggingservice");

echo("AfterloggingServicecall");

InthisexampletestcaseaboveweuseaninstanceofacustomLoggingServiceandcallsomeoperationlog()inthemiddleofourJavaDSLtest.NowdevelopersmightexpecttheloggingservicecalltobedoneinthemiddleoftheJavaCitrustestcasebutifwehavealookattheloggingoutputofthetestwegetatotaldifferentresult:

Expectedoutput

INFOCitrus|STARTINGTESTLoggingTestINFOEchoAction|BeforeloggingServicecallINFOLoggingService|NowcalledcustomloggingserviceINFOEchoAction|AfterloggingServicecallINFOCitrus|TESTSUCCESSLoggingTest

Actualoutput

INFOLoggingService|NowcalledcustomloggingserviceINFOCitrus|STARTINGTESTLoggingTestINFOEchoAction|BeforeloggingServicecallINFOEchoAction|AfterloggingServicecall

CitrusReferenceGuide

27Testcase

Page 28: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

INFOCitrus|TESTSUCCESSLoggingTest

SoifweanalysetheactualloggingoutputweseethattheloggingservicewascalledevenbeforetheCitrustestcasedidstartitsaction.Thisistheresultoftest-designerbuildingupthewholetestcasefirst.Thedesignercollectsalltestactionsfirstininternalmemorycacheandtheexecutesthewholetestcase.SothecustomservicecallontheLoggingServiceisnotpartoftheCitrusJavaDSLtestandthereforeisexecutedimmediatelyatdesigntime.

Wecanfixthiswiththefollowingtest-designercode:

JavaDSLdesigner

importorg.testng.annotations.Test;importcom.consol.citrus.annotations.CitrusTest;importcom.consol.citrus.dsl.testng.TestNGCitrusTestDesigner;

@TestpublicclassLoggingTestDesignerextendsTestNGCitrusTestDesignerprivateLoggingServiceloggingService=newLoggingService();

@CitrusTest(name="LoggingTest")publicvoidloggingTest()echo("BeforeloggingServicecall");

action(newAbstractTestAction()doExecute(TestContextcontext)loggingService.log("Nowcalledcustomloggingservice"););

echo("AfterloggingServicecall");

NowweplacedtheloggingServicecallinsideacustomTestActionimplementationandthereforethispieceofcodeispartoftheCitrusJavaDSLandfollowingfromthatpartoftheCitrustestexecution.Nowwiththatfixwegettheexpectedloggingoutput:

INFOCitrus|STARTINGTESTLoggingTestINFOEchoAction|BeforeloggingServicecallINFOLoggingService|NowcalledcustomloggingserviceINFOEchoAction|AfterloggingServicecallINFOCitrus|TESTSUCCESSLoggingTest

CitrusReferenceGuide

28Testcase

Page 29: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

NowthisisnoteasytounderstandandpeopledidstrugglewiththisseparationofdesigntimeandruntimeofaCitrusJavaDSLtest.ThisiswhywehaveimplementedanewJavaDSLbaseclasscalledtest-runnerthatwedealwithinthenextsection.Beforewecontinuewehavetomentionthatthetest-designerapproachdoesalsoworkforJUnit.AlthoughwehaveonlyseenTestNGsamplecodeinthissectioneverythingisworkingexactlythesamewaywithJUnitframework.Justusethebaseclasscom.consol.citrus.dsl.junit.JUnit4CitrusTestDesignerinstead.

ImportantNeitherTestNGCitrusTestDesignernorJUnit4CitrusTestDesignerimplementationisthreadsafeforparalleltestexecution.Thisissimplybecausethebaseclassisholdingstatetothecurrenttestdesignerinstanceinordertodelegatemethodcallstothisinstance.Thereforeparalleltestmethodexecutionisnotavailable.Fortunatelywehaveaddedathreadsafebaseclassimplementationthatusesresourceinjection.Readmoreaboutthisintestcase-resource-injection.

JavaDSLtestrunner

Thenewtestrunnerconceptsolvestheissuesthatmaycomealongwhenworkingwiththetestdesigner.Wehavealreadyseenasimpleexamplewherethetestdesignerrequiresstrictseparationofdesigntimeandruntime.Thetestrunnerimplementationexecuteseachtestactionimmediately.ThischangestheprerequisitesinsuchthatthetestactionJavaDSLmethodcallscanbemixedwithusualJavacodestatements.Thetheexamplethatwehaveseenbeforeinatestrunnerimplementation:

JavaDSLrunner

importorg.testng.annotations.Test;importcom.consol.citrus.annotations.CitrusTest;importcom.consol.citrus.dsl.testng.TestNGCitrusTestRunner;

@TestpublicclassLoggingTestRunnerextendsTestNGCitrusTestRunnerprivateLoggingServiceloggingService=newLoggingService();

@CitrusTest(name="LoggingTest")publicvoidloggingTest()echo("BeforeloggingServicecall");

loggingService.log("Nowcalledcustomloggingservice");

echo("AfterloggingServicecall");

CitrusReferenceGuide

29Testcase

Page 30: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

WiththenewtestrunnerimplementationasbaseclassweareabletomixJavaDSLmethodcallsandnormalJavacodestatementinourtestinanunlimitedway.ThisexampleabovewillalsocreatetheexpectedloggingoutputasallJavaDSLmethodcallsareexecutedimmediately.

INFOCitrus|STARTINGTESTLoggingTestINFOEchoAction|BeforeloggingServicecallINFOLoggingService|NowcalledcustomloggingserviceINFOEchoAction|AfterloggingServicecallINFOCitrus|TESTSUCCESSLoggingTest

Incontrarytothetestdesignerthetestrunnerimplementationwillnotbuildthecompletetestcasebeforeexecution.EachtestactionisexecutedimmediatelyasitiscalledwithJavaDSLbuildermethods.Thiscreatesamorenaturalwayofcodingtestcasesasyouarealsoabletouseiterations,trycatchblocks,finallysectionsandsoon.

IntheexampleshereTestNGwasusedasunitframework.OfcoursetheexactsameapproachcanalsoapplytoJUnitframework.Justusethebaseclasscom.consol.citrus.dsl.junit.JUnit4CitrusTestRunnerinstead.Feelfreetochoosethebaseclassfortest-designerortest-runnerasyoulike.Youcanalsomixthosetwoapproachesinyourproject.CitrusisabletohandlebothwaysofJavaDSLcodeinaproject.

ImportantTheTestNGCitrusTestRunnerandJUnit4CitrusTestRunnerimplementationisnotthreadsafeforparalleltestexecution.Thisissimplybecausethebaseclassisholdingstatetothecurrenttestrunnerinstanceinordertodelegatemethodcallstothisinstance.Thereforeparalleltestmethodexecutionisnotavailable.Fortunatelywehaveaddedathreadsafebaseclassimplementationthatusesresourceinjection.Readmoreaboutthisintestcase-resource-injection.

Designer/Runnerinjection

Intheprevioussectionswehaveseenthedifferentapproachesfortestdesignerandrunnerimplementations.Uptonowthedecisionwhichimplementationtousewasmadebyextendingoneofthebaseclasses:

com.consol.citrus.dsl.testng.TestNGCitrusTestRunnercom.consol.citrus.dsl.testng.TestNGCitrusTestDesignercom.consol.citrus.dsl.junit.JUnit4CitrusTestRunnercom.consol.citrus.dsl.junit.JUnit4CitrusTestDesigner

CitrusReferenceGuide

30Testcase

Page 31: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ThesefourclassesrepresentthedifferentdesignerandrunnerimplementationsforTestNGorJUnit.NowCitrusalsoprovidesaresourceinjectionmechanismforbothdesignerandrunnerimplementations.Theclassesusingthisfeatureare:

com.consol.citrus.dsl.testng.TestNGCitrusTestcom.consol.citrus.dsl.junit.JUnit4CitrusTest

Sowhatisthedealwiththat?Itissimplewhenlookingatafirstexampleusingresourceinjection:

@TestpublicclassInjectionTestextendsJUnit4CitrusTest

@CitrusTest(name="JUnit4DesignerTest")publicvoiddesignerTest(@CitrusResourceTestDesignerdesigner)designer.echo("Nowworkingondesignerinstance");

@CitrusTest(name="JUnit4RunnerTest")publicvoidrunnerTest(@CitrusResourceTestRunnerrunner)runner.echo("Nowworkingonrunnerinstance");

ThedesignerorrunnerinstanceisinjectedasCitrusresourcetothetestmethodasparameter.Thiswaywecanmixdesignerandrunnerinasingletest.Butthisisnottherealmotivationfortheresourceinjection.Theclearadvantageofthisapproachwithinjecteddesignerandrunnerinstancesissupportformultithreading.IncaseyouwanttoexecutetheCitrustestsinparallelusingmultiplethreadsyouneedtousethisapproach.Thisisbecausetheusualdesignerandrunnerbaseclassesarenotthreadsafe.ThisJUnit4CitrusTestbaseclassisbecausetheresourcesinjectedarenotkeptasstateinthebaseclass.

ThisisourfirstCitrusresourceinjectionusecase.Theframeworkisabletoinjectotherresources,too.Findoutmoreaboutthisinthenextsections.

Testcontextinjection

WhenrunningatestcaseinCitruswemakeuseofbasicframeworkcomponentsandcapabilities.Oneofthesecapabilitiesistousetestvariables,functionsandvalidationmatchers.Uptothispointwehavenotlearnedaboutthesethings.Theywillbedescribedintheupcomingchaptersandsectionsinmoredetail.RightnowIwanttotalkaboutresourceinjectioninCitrus.

CitrusReferenceGuide

31Testcase

Page 32: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

AllthesefeaturementionedaboveareboundtosomeimportantCitruscomponent:theCitrustestcontext.Thetestcontextholdsallvariablesandisabletoresolvefunctionsandmatchers.Ingeneralyouasatesterwillnotneedexplicitaccesstothiscomponentastheframeworkisworkingwithitbehindthescenes.IncaseyouneedsomeaccessforadvancedoperationswiththeframeworkCitrusprovidesaresourceinjection.Letshavealookatthissothingsaregettingmoreclear.

publicclassResourceInjectionITextendsJUnit4CitrusTestDesigner

@Test@CitrusTestpublicvoidresourceInjectionIT(@CitrusResourceTestContextcontext)context.setVariable("myVariable","somevalue");echo("$myVariable");

Asyoucanseewehaveaddedamethodparameteroftypecom.consol.citrus.context.TestContexttothetestmethod.Theannotation@CitrusResourcetellsCitrustoinjectthisparameterwiththeaccordinginstanceoftheobjectforthistest.Nowwehaveeasyaccesstothecontextandallitscapabilitiessuchasvariablemanagement.

OfcoursethesameapproachworkswithTestNG,too.AsTestNGalsoprovidesresourceinjectionmechanismswehavetomakesurethatthedifferentresourceinjectionapproachesdonotinterferewitheachother.SowetellTestNGtonotinjectthisparameterbydeclaringitas@OptionalforTestNG.InadditiontothatweneedtointroducetheparametertoTestNGwiththe@Parametersannotation.OtherwiseTestNGwouldcomplainaboutnotknowingthisparameter.ThefinaltestmethodwithCitrusresourceinjectionlookslikefollows:

publicclassResourceInjectionITextendsTestNGCitrusTestDesigner

@Test@Parameters("context")@CitrusTestpublicvoidresourceInjectionIT(@Optional@CitrusResourceTestContextcontext)context.setVariable("myVariable","somevalue");echo("$myVariable");

CitrusReferenceGuide

32Testcase

Page 33: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Somemoreannotationsneededbuttheresultisthesame.WehaveaccesstotheCitrustestcontext.OfcourseyoucancombinetheresourceinjectionfordifferentCitruscomponents.Justaddmoresome@CitrusResourceannotatedmethodparameterstothetestmethod.

JavaDSLtestbehaviors

WhenusingtheJavaDSLtheconceptofbehaviorsisagoodwaytoreusetestactionblocks.Byputtingtestactionstoatestbehaviorwecaninstantiateandapplythebehaviortodifferenttestcasesmultipletimes.Themechanismisexplainedbestwhenhavingasimplesample:

publicclassFooBehaviorextendsAbstractTestBehaviorpublicvoidapply()variable("foo","test");

echo("fooBehavior");

publicclassBarBehaviorextendsAbstractTestBehaviorpublicvoidapply()variable("bar","test");

echo("barBehavior");

Thelistingaboveshowstwotestbehaviorsthataddveryspecifictestactionsandtestvariablestothetestcase.AsyoucanseethetestbehaviorisabletousethesameJavaDSLactionmethodsasanormaltestcasewoulddo.Insidetheapplymethodblockwedefinethebehaviorstestlogic.Nowoncethisisdonewecanusethebehaviorsinatestcaselikethis:

@CitrusTestpublicvoidbehaviorTest()description("ThisisabehaviorTest");author("Christoph");status(TestCaseMetaInfo.Status.FINAL);

variable("var","test");

applyBehavior(newFooBehavior());

echo("Successfullyappliedbarbehavior");

CitrusReferenceGuide

33Testcase

Page 34: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

applyBehavior(newBarBehavior());

echo("Successfullyappliedbarbehavior");

ThebehaviorisappliedtothetestcasebycallingtheapplyBehaviormethod.Asaresultthebehavioriscalledaddingitslogicatthispointofthetestexecution.Thesamebehaviorcannowbecalledinmultipletestcasessowehaveareusablesetoftestactions.

Description

Inthetestexamplesthatwehaveseensofaryoumayhavenoticedthatatestercangiveadetailedtestdescription.Thetestcasedescriptionclarifiesthetestingpurposeandperspectives.Thedescriptionshouldgiveashortintroductiontotheintendedusecasescenariothatwillbetested.Theusershouldgetafirstimpressionwhatthetestcaseisallaboutaswellasspecialinformationtounderstandthetestscenario.Youcanusefreetextinyourtestdescriptionnolimittothenumberofcharacters.ButbeawareoftheXMLvalidationrulesofwellformedXMLwhenusingtheXMLtestsyntax(e.g.specialcharacterescaping,useofCDATAsectionsmayberequired)

TestActions

Nowwegetclosetothemainpartofwritinganintegrationtest.ACitrustestcasedefinesasequenceofactionsthatwilltakeplaceduringthetest.Actionsbydefaultareexecutedsequentiallyinthesameorderastheyaredefinedinthetestcasedefinition.

XMLDSL

<actions><action>[...]</action><action>[...]</action></actions>

Allactionshaveindividualnamesandpropertiesthatdefinetherespectivebehavior.Citrusoffersawiderangeoftestactionsfromscratch,butyouarealsoabletowriteyourowntestactionsinJavaorGroovyandexecutethemduringatest.actionsgivesyouabriefdescriptionofallavailableactionsthatcanbepartofatestcaseexecution.

CitrusReferenceGuide

34Testcase

Page 35: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Theactionsarecombinedinfreesequencetoeachothersothatthetesterisabletodeclareaspecialactionchaininsidethetest.Theseactionscanbesendingorreceivingmessages,delayingthetest,validatingthedatabaseandsoon.Step-by-stepthetestproceedsthroughtheactionchain.Incaseonesingleactionfailsbyreasonthewholetestcaseisredanddeclarednotsuccessful.

Finallytestsection

Javadevelopersmightbefamiliarwiththeconceptofdoingsomethinginthefinallycodesection.Thefinallysectioncontainsalistoftestactionsthatwillbeexecutedguaranteedattheveryendofthetestcaseeveniferrorsdidoccurduringtheexecutionbefore.Thisistherightplacetotidyupthingsthatwerepreviouslycreatedbythetestlikecleaningupthedatabaseforinstance.Thefinallysectionisdescribedinmoredetailinfinally.Howeverhereisthebasicsyntaxinsideatest.

XMLDSL

<finally><echo><message>Dofinally-regardlessofwhathashappenedbefore</message></echo></finally>

JavaDSLdesigner

@CitrusTestpublicvoidsampleTest()echo("HelloTestFramework");

doFinally(echo("Dofinally-regardlessofanyerrorbefore"));

JavaDSLrunner

@CitrusTestpublicvoidsampleTest()echo("HelloTestFramework");

doFinally().actions(echo("Dofinally-regardlessofanyerrorbefore")

CitrusReferenceGuide

35Testcase

Page 36: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

);

Testmetainformation

Theusercanprovidesomeadditionalinformationaboutthetestcase.Themeta-infosectionattheverybeginningofthetestcaseholdsinformationlikeauthor,statusorcreationdate.Indetailthemetainformationisspecifiedlikethis:

XMLDSL

<testcasename="metaInfoTest"><meta-info><author>ChristophDeppisch</author><creationdate>2008-01-11</creationdate><status>FINAL</status><last-updated-by>ChristophDeppisch</last-updated-by><last-updated-on>2008-01-11T10:00:00</last-updated-on></meta-info><description>...</description><actions>...</actions></testcase>

JavaDSLdesignerandrunner

@CitrusTestpublicvoidsampleTest()description("ThisisaTest");author("Christoph");status(Status.FINAL);

echo("HelloCitrus!");

Thestatusallowsfollowingvalues:DRAFT,READY_FOR_REVIEW,DISABLED,FINAL.Themeta-datainformationtoatestisquiteimportanttogivethereaderafirstinformationaboutthetest.Itisalsopossibletogeneratetestdocumentationusingthismeta-datainformation.Thebuilt-inCitrusdocumentationgeneratesHTMLorExceldocumentsthatlistalltestswiththeirmetadatainformationanddescription.

CitrusReferenceGuide

36Testcase

Page 37: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

NoteTestswiththestatusDISABLEDwillnotbeexecutedduringatestsuiterun.SosomeonecanjuststartaddingplannedtestcasesthatarenotfinishedyetinstatusDRAFT.Incaseatestisnotrunnableyetbecauseitisnotfinished,someonemaydisableatesttemporarilytoavoidcausingfailuresduringatestrun.UsingthesedifferentstatusesonecaneasilysetuptestplansandreviewtheprogressoftestcoveragebycomparingthenumberofDRAFTteststothoseintheFINALstate.

NowyouknowthepossibilitieshowtowriteCitrustestcasesinXMLorJava.Pleasechoosewhatevercodelanguagetypeyouwant(Java,XML,Springbeansyntax)inordertowriteCitrustestcases.DevelopersmaychooseJava,testerswithoutcodingexperiencemayrunbestwiththeXMLsyntax.WeareconstantlyworkingonevenmoretestwritinglanguagesupportsuchasGroovy,Scala,Xtext,andsoon.IngeneralyoucanmixthedifferentlanguagetypesjustasyoulikewithinyourCitrusprojectwhichgivesyouthebestofflexibility.

CitrusReferenceGuide

37Testcase

Page 38: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TestvariablesTheusageoftestvariablesisacoreconceptwhenwritinggoodmaintainabletests.Thekeyidentifiersofatestcaseshouldbeexposedastestvariablesattheverybeginningofatest.Thiswayhardcodedidentifiersandmultipleredundantvaluesinsidethetestcanbeavoidedfromscratch.Asatesteryoudefinealltestvariablesattheverybeginningofyourtest.

XMLDSL

<variables><variablename="text"value="HelloTestFramework"/><variablename="customerId"value="123456789"/></variables>

JavaDSLdesignerandrunner

variable("text","HelloTestFramework");variable("customerId","123456789");

Theconceptoftestvariablesisessentialwhenwritingcomplextestswithlotsofidentifiersandsemanticdata.Testvariablesarevalidforthewholetestcase.Youcanreferencethemseveraltimesusingacommonvariableexpression"$variable-name".Itisgoodpracticetoprovideallimportantentitiesastestvariables.Thismakesthetesteasiertomaintainandmoreflexible.Allessentialentitiesandidentifiersarepresentrightatthebeginningofthetest,whichmayalsogivetheopportunitytoeasilycreatetestvariantsbysimplychangingthevariablevaluesforothertestscenarios.

Thenameofthevariableisarbitrary.Feelfreetospecifyanynameyoucanthinkof.OfcourseyouneedtobecarefulwithspecialcharactersandreservedXMLentitieslike'&','<','>'.IfyouarefamiliarwithJavaoranyotherprogramminglanguagesimplythinkofthenamingrulesthereandyouwillbefinewithworkingonCitrusvariables,too.Thevalueofavariablecanbeanycharactersequence.ButagainbeawareofspecialXMLcharacterslike"<"thatneedtobeescaped("<")whenusedinvariablevalues.

Theadvantageofvariablesisobvious.Oncedeclaredthevariablescanbereferencedmanytimesinthetest.Thismakesitveryeasytovarydifferenttestcasesbyadjustingthevariablesfordifferentmeans(e.g.usedifferenterrorcodesintestcases).

CitrusReferenceGuide

38Testvariables

Page 39: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Globalvariables

Thelastsectiontoldustousevariablesastheyareveryusefulandextendthemaintainabilityoftestcases.Nowthateverytestcasedefineslocalvariablesyoucanalsodefineglobalvariables.Theglobalvariablesarevalidinalltestsbydefault.Thisisagoodopportunitytodeclareconstantvaluesforalltests.AsthesevariablesareglobalweneedtoaddthosetothebasicSpringapplicationcontextfile.ThefollowingexampledemonstrateshowtoaddglobalvariablesinCitrus:

<citrus:global-variables><citrus:variablename="projectName"value="CitrusIntegrationTesting"/><citrus:variablename="userName"value="TestUser"/></citrus:global-variables>

WeaddtheSpringbeancomponenttotheapplicationcontextfile.Thecomponentreceivesalistofname-valuevariableelements.Youcanreferencetheglobalvariablesinyourtestcasesasusual.

Anotherpossibilitytosetglobalvariablesistoloadthosefromexternalpropertyfiles.Thismaygiveyoumorepowerfulglobalvariableswithuserspecificpropertiesforinstance.Seehowtoloadpropertyfilesasglobalvariablesinthisexample:

<citrus:global-variables><citrus:filepath="classpath:global-variable.properties"/></citrus:global-variables>

Wehavejustaddedafilepathreferencetotheglobalvariablescomponent.Citrusloadsthepropertyfilecontentasglobaltestvariables.Youcanmixpropertyfileandname-valuepairvariabledefinitionsintheglobalvariablescomponent.

NoteTheglobalvariablescanhavevariableexpressionsandCitrusfunctions.Itispossibletousepreviouslydefinedglobalvariablesasvaluesofnewvariables,likeinthisexample:

user=Citrusgreeting=Hello$user!date=citrus:currentDate('yyyy-MM-dd')

CreatevariableswithCDATA

CitrusReferenceGuide

39Testvariables

Page 40: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

WhenusingthXMLtestcaseDSLwecannothaveXMLvariablevaluesoutofthebox.ThiswouldinterferewiththeXMLDSLelementsdefinedintheCitrustestcaseXSDschema.YoucanuseCDATAsectionswithinthevariablevalueelementinordertodothisthough.

<variables><variablename="persons"><value><data><![CDATA[<persons><person><name>Theodor</name><age>10</age></person><person><name>Alvin</name><age>9</age></person></persons>]]></data></value></variable></variables>

ThatishowyoucanuseXMLvariablevaluesintheXMLDSL.IntheJavaDSLwedonothavetheseproblems.

CreatevariableswithGroovy

Youcanalsouseascripttocreatevariablevalues.Thisisextremelyhandywhenyouhaveverycomplexvariablevalues.JustcodeasmallGroovyscriptforinstanceinordertodefinethevariablevalue.Asmallsampleshouldgiveyoutheideahowthatworks:

<variables><variablename="avg"><value><scripttype="groovy">

</script></value>

CitrusReferenceGuide

40Testvariables

Page 41: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</variable><variablename="sum"><value><scripttype="groovy">

</script></value></variable></variables>

Weusethescriptcoderightinsidethevariablevaluedefinition.Thevalueofthevariableistheresultofthelastoperationperformedwithinthescript.Forlongerscriptcodetheuseof<![CDATA[]]>sectionsisrecommended.

CitrususesthejavaxScriptEnginemechanisminordertoevaluatethescriptcode.BydefaultGroovyissupportedinanyCitrusproject.SoyoucanaddadditionalScriptEngineimplementationstoyourprojectandsupportotherscripttypes,too.

Escapingvariablesexpression

Thetestvariablesexpressionsyntax"$variable-name"ispreservedtoevaluatetoatestvariablewithinthecurrenttestcontext.Howeverthesamesyntaxmaybepartofamessagecontentasis.Soyouneedtosomehowescapethesyntaxfrombeeinginterpretedastestvariablesyntax.Youcandothisbyusingthevariableexpressionescaping//charactersequencewrappingtheactualvariablenamelikethis

Thisisaescapedvariableexpression$//escaped//andshouldnotleadtounknownvariableexceptionswithinCitrus.

Theescapedexpression$//escaped//abovewillresultinthestring$escapedwhereescapedisnottreatedasatestvariablenamebutasanormalstringinthemessagepayload.ThiswayyouareabletohavethesamevariablesyntaxinamessagecontentwithoutinterferingwiththeCitrusvariableexpressionsyntax.AsaresultCitruswillnotcomplainaboutnotfindingthetestvariableescapedinthecurrentcontext.Thevariablesyntaxescapingcharacters//areautomaticallyremovedwhentheexpressionisprocessedbyCitrus.Sowewillgetthefollowingresultafterprocessing.

Thisisaescapedvariableexpression$escapedandshouldnotleadtounknownvariableexceptionswithinCitrus.

CitrusReferenceGuide

41Testvariables

Page 42: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

CitrusReferenceGuide

42Testvariables

Page 43: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

RunningtestsCitrustestcasesarenothingbutJavaclassesthatgetexecutedwithinaJavaruntimeenvironment.EachCitrustestthereforerelatestoaJavaclassrepresentingaJUnitorTestNGunittest.AsoptionaladdonaCitrustestcanhaveaXMLtestdeclarationfile.ThisisforthoseofyouthatdonotwanttocodeinJava.InthiscasetheXMLpartholdsallactionstotellCitruswhatshouldhappeninthetestcase.TheJavapartwillthenjustberesponsiblefortestexecutionandisnotlikelytobechangedatall.InthefollowingsectionsweconcentrateontheJavapartandthetestexecutionmechanism.

IfyoucreatenewtestcasesinCitrus-forinstanceviaMavenpluginorANTbuildscript-Citrusgeneratesbothpartsinyourtestdirectory.Forexample:ifyoucreateanewtestnamedMyFirstCitrusTestyouwillfindthesetwofilesasaresult:

src/it/tests/com/consol/citrus/MyFirstCitrusTest.xmlsrc/it/java/com/consol/citrus/MyFirstCitrusTest.java

NoteIfyouprefertojustwriteJavacodeyoucanthrowawaytheXMLpartimmediatelyandcontinueworkingwiththeJavapartonly.IncaseyouarefamiliarwithwritingJavacodeyoumayjustskipthetesttemplategenerationviaMavenorANTandpreferablyjustcreatenewCitrusJavatestclassesonyourown.

Withthecreationofthistestwehavealreadymadeaveryimportantdecision.Duringcreation,Citrusasksyouwhichexecutionframeworkshouldbeusedforthistest.Therearebasicallythreeoptionsavailable:testngandjunit.

SowhyisCitrusrelatedtoUnittestsalthoughitisintendedtobeaframeworkforintegrationtesting?Theanswertothisquestionisquitesimple:ThisisbecauseCitruswantstobenefitfrombothJUnitandTestNGforJavatestexecution.BoththeJUnitandTestNGJavaAPIsoffervariouswaysofexecutionandbothframeworksarewidelysupportedbyothertools(e.g.continuousbuild,buildlifecycle,developmentIDE).

Usersmightalreadyknowoneoftheseframeworksandthechancesaregoodthattheyarefamiliarwithatleastoneofthem.EverythingyoucandowithJUnitandTestNGtestcasesyoucandowithCitrustestsalso.IncludethemintoyourMavenbuildlifecycle.ExecutetestsfromyourIDE(Eclipse,IDEAorNetBeans).Includethemintoa

CitrusReferenceGuide

43Run

Page 44: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

continuousbuildtool(e.g.Jenkins).GeneratetestexecutionreportsandtestcoveragereportswithSonar,Coberturaandsoon.ThepossibilitieswithJUnitandTestNGareamazing.

SoletushaveacloserlookattheCitrusTestNGandJUnitintegration.

RunwithTestNG

TestNGstandsfornextgenerationtestingandhashadagreatinfluenceinaddingJavaannotationstotheunittestcommunity.CitrusisabletogenerateTestNGJavaclassesthatareexecutableastestcases.SeethefollowingstandardtemplatethatCitruswillgeneratewhenhavingnewtestcases:

packagecom.consol.citrus.samples;

importorg.testng.annotations.Test;importcom.consol.citrus.annotations.CitrusXmlTest;importcom.consol.citrus.testng.AbstractTestNGCitrusTest;

/***TODO:Description**@authorUnknown*/@TestpublicclassSampleITextendsAbstractTestNGCitrusTest@CitrusXmlTest(name="SampleIT")publicvoidsampleTest()

IfyouarefamiliarwithTestNGyouwillseethatthegeneratedJavaclassisnothingbutanormalTestNGtestclass.WejustextendabasicCitrusTestNGclasswhichenablestheCitrustestexecutionfeaturesforus.BesidesthatwehaveausualTestNG@Testannotationplacedonourclasssoallmethodsinsidetheclasswillbeexecutedasseparatetestcase.

ThegoodnewsisthatwecanstillusethefantasticTestNGfeaturesinourtestclass.Youcanthinkofparalleltestexecution,testgroups,setupandteardownoperationsandsoon.Justtogiveanexamplewecansimplyaddatestgrouptoourtestlikethis:

@Test(groups="long-running")

FormoreinformationonTestNGpleasevisittheofficialhomepage,whereyoufindacompletereferencedocumentation.

CitrusReferenceGuide

44Run

Page 45: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

YoumighthavenoticedthattheexampleaboveloadstestcasesfromXML.Thisiswhyweareusingthe@CitrusXmlTestannotation.AgainthisapproachisforpeoplethatwanttowritenoJavacode.ThetestlogicisthenprovidedintheXMLtestdefinition.WediscussXMLtestsinCitrusinmoredetailinrun-xml-tests.NextletshavealookataTestNGJavaDSLtest.

WhenwritingtestsinpureJavawehaveprettymuchtheexactsamelogicthatappliestoexecutingCitrustestcases.TheCitrustestextendsfromaTestNGbaseclassandusesthenormal@Testannotationsonmethodorclasslevel.HereisashortsampleTestNGJavaclassforthis:

importorg.testng.annotations.Test;importcom.consol.citrus.annotations.CitrusTest;importcom.consol.citrus.dsl.testng.TestNGCitrusTestDesigner;

@TestpublicclassMyFirstTestDesignerextendsTestNGCitrusTestDesigner@CitrusTest(name="MyFirstIT")publicvoidmyFirstTest()description("Firstexampleshowingthebasictestcasedefinitionelements!");

variable("text","HelloTestFramework");

echo("$test");

YouseetheclassisquitesimilartotheXMLtestvariation.NowweextendaCitrustestdesignerclasswhichenablestheJavaDSLfeaturesinadditiontotheTestNGtestexecutionforus.Thebasic@TestannotationforTestNGhasnotchanged.WestillhaveausualTestNGclasswiththepossibilityofseveralmethodseachrepresentingaseparateunittest.

Nowwhathaschangedisthe@CitrusTestannotation.NowtheCitrustestlogicisplaceddirectlyasthemethodbodywithusingtheJavadomainspecificlanguagefeatures.TheXMLCitrustestpartisnotnecessaryanymore.IfyouarewonderingaboutthedesignersuperclassandtheJavaDSLmethodsforaddingthetestlogictoyourtestpleasebepatientwewilllearnmoreabouttheJavaDSLfeaturesinthisreferenceguidelateron.

UptonowwejustconcentrateontheTestNGintegrationthatisquiteeasyisn'tit.

UsingTestNGDataProviders

CitrusReferenceGuide

45Run

Page 46: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TestNGasaframeworkcomeswithlotsofgreatfeaturessuchasdataproviders.Dataprovidersexecuteatestcaseseveraltimes.Eachtestexecutiongetsaspecificparametervalue.WithCitrusyoucanusethosedataproviderparametersinsidethetestasvariables.SeethenextlistingonhowtouseTestNGdataprovidersinCitrus:

publicclassDataProviderITextendsAbstractTestNGCitrusTest

@CitrusXmlTest@CitrusParameters("message")@Test(dataProvider="messageDataProvider")publicvoidDataProviderIT(ITestContexttestContext)

@DataProviderpublicObject[][]messageDataProvider()returnnewObject[][]"HelloWorld!","HalloWelt!","HiCitrus!",;

AbovetestcasemethodisannotatedwithTestNGdataprovidercalledmessageDataProvider.Inthesameclassyoucanwritethedataproviderthatreturnsalistofparametervalues.TestNGwillexecutethetestcaseseveraltimesaccordingtotheprovidedparameterlist.Eachexecutionisshippedwiththerespectiveparametervalue.Accordingtothe@CitrusParameterannotationthetestwillhaveatestvariablecalledmessagethatisaccessibleasusual.

RunwithJUnit

JUnitisaverypopularunittestframeworkforJavaapplicationswidelyacceptedandwidelysupportedbymanytools.IngeneralCitrussupportsbothJUnitandTestNGastestexecutionframeworks.AlthoughtheTestNGcustomizationfeaturesareslightlymorepowerfulthanthoseofferedbyJUnityouasaCitrususershouldbeabletousetheframeworkofyourchoice.Thecompletesupportforexecutingtestcaseswithpackagescansandmultipleannotatedmethodsisgivenforbothframeworks.IfyouchoosejunitasexecutionframeworkCitrusgeneratesaJavafilethatlookslikethis:

packagecom.consol.citrus.samples;

importorg.junit.Test;

CitrusReferenceGuide

46Run

Page 47: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

importcom.consol.citrus.annotations.CitrusXmlTest;importcom.consol.citrus.junit.AbstractJUnit4CitrusTest;

/***TODO:Description**@authorUnknown*/publicclassSampleITextendsAbstractJUnit4CitrusTest@Test@CitrusXmlTest(name="SampleIT")publicvoidsampleTest()

JUnitandTestNGasframeworksrevealslightdifferences,buttheideaisthesame.WeextendabaseJUnitCitrustestclassandhaveonetomanytestmethodsthatloadtheXMLCitrustestcasesforexecution.AsyoucanseethetestclasscanholdseveralannotatedtestmethodsthatgetexecutedasJUnittests.ThefinethinghereisthatwearestillabletouseallJUnitfeaturessuchasbefore/aftertestactionsorenable/disabletests.

TheJavaJUnitclassesaresimplyresponsibleforloadingandexecutingtheCitrustestcases.CitrustakescareonloadingtheXMLtestasafilesystemresourceandtosetuptheSpringapplicationcontext.Thetestisexecutedandsuccess/failurestateisreportedexactlylikeausualJUnitunittestwoulddo.ThisalsomeansthatyoucanexecutethisCitrusJUnitclasslikeeveryotherJUnittest,especiallyoutofanyJavaIDE,withMaven,withANTandsoon.ThismeansthatyoucaneasilyincludetheCitrustestexecutionintoyousoftwarebuildinglifecycleandcontinuousbuild.

TipSonowweknowbothTestNGandJUnitsupportinCitrus.Whichframeworkshouldsomeonechoose?Tobehonest,thereisnoeasyanswertothisquestion.Thebasicfeaturesareequivalent,butTestNGoffersbetterpossibilitiesfordesigningmorecomplextestsetupwithtestgroupsandtasksbeforeandafteragroupoftests.ThisiswhyTestNGisthedefaultoptioninCitrus.Butintheendyouhavetodecideonyourownwhichframeworkfitsbestforyourproject.

Thefirstexampleseenhereisusing@CitrusXmlTestannotationinordertoloadaXMLfileastest.TheJavapartisthenjustanemptyenvelopeforexecutingthetestwithJUnit.ThisapproachisforthoseofyouthatarenotfamiliarwithJavaatall.YoucanfindmoreinformationonloadingXMLfilesasCitrustestsinrun-xml-tests.SecondlyofcoursewealsohavethepossibilitytousetheCitrusJavaDSLwithJUnit.Seethefollowingexampleonhowthislookslike:

CitrusReferenceGuide

47Run

Page 48: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

packagecom.consol.citrus.samples;

importcom.consol.citrus.annotations.CitrusTest;importcom.consol.citrus.dsl.JUnit4CitrusTestDesigner;importorg.junit.Test;

/***TODO:Description**@authorUnknown*/publicclassSampleITextendsJUnit4CitrusTestDesigner

@Test@CitrusTestpublicvoidEchoSampleIT()variable("time","citrus:currentDate()");echo("HelloCitrus!");echo("CurrentTimeis:$time");

@Test@CitrusTest(name="EchoIT")publicvoidechoTest()echo("HelloCitrus!");

TheJavaDSLtestcaselooksquitefamiliaraswealsousetheJUnit4@Testannotationinordertomarkourtestforunittestexecution.Inadditiontothatweadda@CitrusTestannotationandextendfromabasicJUnit4CitrustestdesignerwhichenablestheJavadomainspecificlanguagefeatures.TheCitrustestlogicgoesdirectlytothemethodblock.ThereisnoneedforaXMLtestfileanymore.

Asyoucanseethe@CitrusTestannotationsupportsmultipletestmethodsinonesingleclass.EachtestispreparedandexecutedseparatelyjustasyouknowitfromJUnit.YoucandefineanexplicitCitrustestnamethatisusedinCitrustestreports.Ifnoexplicittestnameisgiventhetestmethodnamewillbeusedasatestname.

IfyouneedtoknowmoredetailsaboutthetestdesignerandonhowtousetheCitrusJavaDSLjustcontinuewiththisreferenceguide.Wewilldescribethecapabilitiesindetaillateron.

RunningXMLtests

CitrusReferenceGuide

48Run

Page 49: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Nowwealsousethe@CitrusXmlTestannotationintheJavaclass.ThisannotationmakesCitrussearchforaXMLfilethatrepresentstheCitrustestwithinyourclasspath.LateronwewillalsodiscussanotherCitrusannotation(@CitrusTest)whichstandsfordefiningtheCitrustestjustwithJavadomainspecificlanguagefeatures.FornowwecontinuetodealwiththeXMLCitrustestexecution.

ThedefaultnamingconventionrequiresaXMLfilewiththetestsnameinthesamepackagethattheJavaclassisplacedin.InthebasicexampleabovethismeansthatCitrussearchesforaXMLtestfileincom/consol/citrus/samples/SampleIT.xml.YoutellCitrustosearchforanotherXMLfilebyusingthe@CitrusXmlTestannotationproperties.Followingannotationpropertiesarevalid:

name:Listoftestcasenamestoexecute.NamesalsodefineXMLfilenamestolookfor(.xmlfileextensionisnotneededhere).packageName:CustompackagelocationfortheXMLfilestoloadpackageScan:ListofpackagesthatareautomaticallyscannedforXMLtestfilestoexecute.ForeachXMLfilefoundseparatetestisexecuted.NotethatthisperformsaJavaClasspathpackagescansoallXMLfilesinpackageareassumedtobevalidCitrusXMLtestcases.InordertominimizetheamountofaccidentallyloadedXMLfilesthescanwillonlyloadXMLfileswith*/Test.xmland*/IT.xmlfilenamepattern.

YoucanalsomixthevariousCitrusXmlTestannotationpatternsinasingleJavaclass.SoweareabletohaveseveraltestcasesinonesingleJavaclass.EachannotatedmethodrepresentsoneormoreCitrusXMLtestcases.Sethefollowingexampletoseewhatthisisabout.

@TestpublicclassSampleITextendsAbstractTestNGCitrusTest@CitrusXmlTest(name="SampleIT")publicvoidsampleTest()

@CitrusXmlTest(name="SampleIT","AnotherIT")publicvoidmultipleTests()

@CitrusXmlTest(name="OtherIT",packageName="com.other.testpackage")publicvoidotherPackageTest()

@CitrusXmlTest(packageScan="com.some.testpackage","com.other.testpackage")publicvoidpackageScanTest()

CitrusReferenceGuide

49Run

Page 50: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Youarefreetocombinethesetestannotationsasyoulikeinyourclass.AsthewholeJavaclassisannotatedwiththeTestNG@Testannotationeachmethodgetsexecutedautomatically.CitruswillalsotakecareonexecutingeachXMLtestcaseasaseparateunittest.SothetestreportswillhavetheexactnumberofexecutedtestsandtheJUnit/TestNGtestreportsdohavetheexacttestoutlineforfurtherusage(e.g.incontinuousbuildreports).

NoteWhentestexecutiontakesplaceeachtestmethodannotationisevaluatedinsequence.XMLtestcasesthatmatchseveraltimes,forinstancebyexplicitnamereferenceandapackagescanwillbeexecutedseveraltimesrespectively.

Thebestthingaboutusingthe@CitrusXmlTestannotationisthatyoucancontinuetousethefabulousTestNGcapabilities(e.g.testgroups,invocationcount,threadpools,dataproviders,andsoon).

SonowwehaveseenhowtoexecuteaCitrusXMLtestwithTestNG.

CitrusReferenceGuide

50Run

Page 51: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ConfigurationYouhaveseveraloptionsincustomizingtheCitrusprojectconfiguration.Citrususesdefaultsettingsthatcanbeoverwrittentosomeextend.AsaframeworkCitrusinternallyworkswiththeSpringIoCcontainer.SoCitruswillstartaSpringapplicationcontextandregisterseveralcomponentsasSpringbeans.Youcancustomizethebehaviorofthesebeansandyoucanaddcustomsettingsbysettingsystemproperties.

CitrusSpringXMLapplicationcontext

CitrusstartsaSpringapplicationcontextandaddssomedefaultSpringbeancomponents.BydefaultCitruswillloadsomeinternalSpringJavaconfigclassesdefiningthosebeancomponents.Atsomepointyoumightaddsomecustombeanstothatbasicapplicationcontext.ThisiswhyCitruswillsearchforcustomSpringapplicationcontextfilesinyourproject.Theseareautomaticallyloaded.

BydefaultCitruslooksforcustomXMLSpringapplicationcontextfilesinthislocation:classpath*:citrus-context.xml.Soyoucanaddafilenamedcitrus-context.xmltoyourprojectclasspathandCitruswillloadallSpringbeansautomatically.

ThelocationofthisfilecanbecustomizedbysettingaSystempropertycitrus.spring.application.context.SoyoucancustomizetheXMLSpringapplicationcontextfilelocation.TheSystempropertyissettablewithMavensurefireandfailsafepluginforinstanceorviaJavabeforetheCitrusframeworkgetsloaded.

SeethefollowingsampleXMLconfigurationwhichisanormalSpringbeanXMLconfiguration:

<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:citrus="http://www.citrusframework.org/schema/config"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/confighttp://www.citrusframework.org/schema/config/citrus-config.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"

<citrus:schema-repositoryid="schemaRepository"/>

</beans>

CitrusReferenceGuide

51Configuration

Page 52: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

NowyoucanaddsomeSpringbeansandyoucanusetheCitrusXMLcomponentssuchasschema-repositoryforaddingcustombeansandcomponentstoyourCitrusproject.CitrusprovidesseveralnamespacesforcustomSpringXMLcomponents.Thesearedescribedinmoredetailintherespectivechaptersandsectionsinthisreferenceguide.

TipYoucanalsouseimportstatementsinthisSpringapplicationcontextinordertoloadotherconfigurationfiles.SoyouarefreetomodularizeyourconfigurationinseveralfilesthatgetloadedbyCitrus.

CitrusSpringJavaconfig

UsingXMLSpringapplicationcontextconfigurationisthedefaultbehaviorofCitrus.HoweversomepeoplemightpreferpureJavacodeconfiguration.YoucandothatbyaddingaSystempropertycitrus.spring.java.configwithacustomSpringJavaconfigclassasvalue.

System.setProperty("citrus.spring.java.config",MyCustomConfig.class.getName())

CitruswillloadtheSpringbeanconfigurationsinMyCustomConfig.classasJavaconfigthen.SeethefollowingexampleforcustomSpringJavaconfiguration:

importcom.consol.citrus.TestCase;importcom.consol.citrus.report.*;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;

@ConfigurationpublicclassMyCustomConfig

@Bean(name="customTestListener")publicTestListenercustomTestListener()returnnewPlusMinusTestReporter();

privatestaticclassPlusMinusTestReporterextendsAbstractTestListenerimplementsTestReporter

/**Logger*/privateLoggerlog=LoggerFactory.getLogger(CustomBeanConfig.class);

privateStringBuildertestReport=newStringBuilder();

@OverridepublicvoidonTestSuccess(TestCasetest)

CitrusReferenceGuide

52Configuration

Page 53: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

testReport.append("+");

@OverridepublicvoidonTestFailure(TestCasetest,Throwablecause)testReport.append("-");

@OverridepublicvoidgenerateTestResults()log.info(testReport.toString());

@OverridepublicvoidclearTestResults()testReport=newStringBuilder();

YoucanalsomixXMLandJavaconfigurationsoCitruswillloadbothconfigurationtotheSpringbeanapplicationcontextonstartup.

Citrusapplicationproperties

TheCitrusframeworkreferencessomebasicSystempropertiesthatcanbeoverwritten.ThepropertiesareloadedfromJavaSystemandarealsosettableviapropertyfile.Justaddapropertyfilenamedcitrus-application.propertiestoyourprojectclasspath.Thispropertyfilecontainscustomizedsettingssuchas:

citrus.spring.application.context=classpath*:citrus-custom-context.xmlcitrus.spring.java.config=com.consol.citrus.config.MyCustomConfigcitrus.file.encoding=UTF-8citrus.default.message.type=XMLcitrus.xml.file.name.pattern=/**/*Test.xml,/**/*IT.xml

Citrusloadstheseapplicationpropertiesatstartup.AllpropertiesarealsosettablewithJavaSystemproperties.Thelocationofthecitrus-application.propertiesiscustomizablewiththeSystempropertycitrus.application.config.

System.setProperty("citrus.application.config","custom/path/to/citrus-application.properties"

CitrusReferenceGuide

53Configuration

Page 54: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Atthemomentyoucanusethesepropertiesforcustomization:

citrus.spring.application.context:FilelocationforSpringXMLconfigurationscitrus.spring.java.config:ClassnameforSpringJavaconfigcitrus.file.encoding:DefaultfileencodingusedinCitruswhenreadingandwritingfilecontentcitrus.default.message.type:Defaultmessagetypeforvalidatingpayloadscitrus.xml.file.name.pattern:FilenamepatternsusedforXMLtestfilepackagescan

CitrusReferenceGuide

54Configuration

Page 55: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

EndpointsInoneofthepreviouschapterswehavediscussedthebasictestcasestructureasweintroducedvariablesandtestactions.Thesectioncontainsalistoftestactionsthattakeplaceduringthetestcase.Eachtestactionisexecutedinsequentialorderbydefault.Citrusoffersseveralbuilt-intestactionsthattheusercanchoosefromtoconstructacomplextestingworkflowwithouthavingtocodeeverythingfromscratch.InparticularCitrusaimstoprovideallthetestactionsthatyouneedaspredefinedcomponentsreadyforyoutouse.Thegoalistominimizethecodingeffortforyousoyoucanconcentrateonthetestlogicitself.

ExactlythesameapproachisusedinCitrustoprovideready-to-useendpointcomponentforconnectingtodifferentmessagetransports.Thereareseveralwaysinanenterpriseapplicationtoexchangemessageswithsomeotherapplication.WehavesynchronousinterfaceslikeHttpandSOAPWebServices.WehaveasynchronousmessagingwithJMSorfiletransferFTPinterfaces.

Citrusprovidesendpointcomponentsasclientandservertoconnectwiththesetypicalmessagetransports.SoyouasatestermustnotcareabouthowtosendamessagetoaJMSqueue.TheCitrusendpointsareconfiguredintheSpringapplicationcontextandreceiveendpointspecificpropertieslikeendpointuriorportsormessagetimeoutsasconfiguration.

ThenextfigureshowsatypicalmessagesendingendpointcomponentinCitrus:

Theendpointproducerpublishesmessagestoadestination.ThisdestinationcanbeaJMSqueue/topic,aSOAPWebServiceendpoint,aHttpURL,aFTPfolderdestinationandsoon.Theproducerjusttakesapreviouslydefinedmessagedefinition(headerandpayload)andsendsittothemessagedestination.

SimilartothatCitrusdefinestheseveralendpointconsumercomponentstoconsumemessagesfromdestinations.ThiscanbeasimplesubscriptiononmessagechannelsandJMSqueues/topics.IncaseofSOAPWebServicesandHttpGET/POSTthingsare

CitrusReferenceGuide

55Endpoints

Page 56: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

morecomplicatedaswehavetoprovideaservercomponentthatclientscanconnectto.Wewillhandleserverrelatedcommunicationinmoredetaillateron.Fornowtheendpointconsumercomponentinitsmostsimplewayisdefinedlikethis:

ThisisallyouneedtoknowaboutCitrusendpoints.WehavementionedthattheendpointsaredefinedintheSpringapplicationcontext.Let'shaveasimpleexamplethatshowsthebasicidea:

<citrus-jms:endpointid="helloServiceEndpoint"destination-name="Citrus.HelloService.Request.Queue"connection-factory="myConnectionFacotry"/>

ThisisasimpleJMSendpointcomponentinCitrus.TheendpointXMLbeandefinitionfollowsacustomXMLnamespaceanddefinesendpointspecificpropertiesliketheJMSdestinationnameandtheJMSconnectionfactory.Theendpointidisasignificantpropertyasthetestcaseswillreferencethisendpointwhensendingandreceivingmessagesbyitsidentifier.

Inthenextsectionsyouwilllearnhowatestcaseusesthoseendpointcomponentsforproducingandconsumingmessages.

Sendmessageswithendpoints

Theactioninatestcasepublishesmessagestoadestination.Theactualmessagetransportconnectionisdefinedwiththeendpointcomponent.Thetestcasesimplydefinesthemessagecontentsandreferencesapredefinedmessageendpointcomponentbyitsidentifier.EndpointspecificconfigurationsarecentralizedintheSpringbeanapplicationcontextwhilemultipletestcasescanreferencetheendpointtoactuallypublishtheconstructedmessagetoadestination.ThereareseveralmessageendpointimplementationsinCitrusavailablerepresentingdifferenttransportprotocolslikeJMS,SOAP,HTTP,TCP/IPandmanymore.

Againthetypeoftransporttouseisnotspecifiedinsidethetestcasebutinthemessageendpointdefinition.Theseparationofconcerns(testcase/messagesendertransport)givesusagoodflexibilityofourtestcases.Thetestcasedoesnotknowanythingaboutconnectionfactories,queuenamesorendpointuri,connectiontimeoutsandsoon.The

CitrusReferenceGuide

56Endpoints

Page 57: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

transportinternalsunderneathasendingtestactioncanchangeeasilywithoutaffectingthetestcasedefinition.WewillseelaterinthisdocumenthowtocreatedifferentmessageendpointsforvarioustransportsinCitrus.Fornowweconcentrateonconstructingthemessagecontenttobesent.

Weassumethatthemessage'spayloadwillbeplainXMLformat.CitrususesXMLasthedefaultdataformatformessagepayloaddata.ButCitrusisnotlimitedtoXMLmessageformatthough;youcanalwaysdefineothermessagedataformatssuchasJSON,plaintext,CSV.AsXMLisstillaverypopularmessageformatinenterpriseapplicationsandmessage-basedsolutionarchitectureswehavethisasadefaultformat.AnywayCitrusworksbestonXMLpayloadsandyouwillseealotofexamplecodeinthisdocumentusingXML.Finallyletushavealookatafirstexamplehowasendingactionisdefinedinthetest.

XMLDSL

<testcasename="SendMessageTest"><description>Basicsendmessageexample</description>

<actions><sendendpoint="helloServiceEndpoint"><message><payload><TestMessage><Text>Hello!</Text></TestMessage></payload></message><header><elementname="Operation"value="sayHello"/></header></send></actions></testcase>

Nowletshaveacloserlookatthesendingaction.The'endpoint'attributemightcatchyourattentionfirst.ThisattributereferencesthemessageendpointinCitrusconfigurationbyitsidentifier.Aspreviouslymentionedthemessageendpointdefinitionlivesinaseparateconfigurationfileandcontainstheactualmessagetransportsettings.Inthisexamplethe"helloServiceEndpoint"isreferencedwhichisaJMSendpointforsendingoutmessagestoaJMSqueueforinstance.

CitrusReferenceGuide

57Endpoints

Page 58: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Thetestcaseisnotawareofanytransportdetails,becauseitdoesnothaveto.Theadvantagesareobvious:Ontheonehandmultipletestcasescanreferencethemessageendpointdefinitionforbetterreuse.Secondlytestcasesareindependentofmessagetransportdetails.Soconnectionfactories,usercredentials,endpointurivaluesandsoonarenotpresentinthetestcase.

Inotherwordsthe"endpoint"attributeofthe<send>elementspecifieswhichmessageendpointdefinitiontouseandthereforewherethemessageshouldgoto.OnceagainallavailablemessageendpointsareconfiguredinaseparateCitrusconfigurationfile.Besuretoalwayspicktherightmessageendpointtypeinordertopublishyourmessagetotherightdestination.

IfyoudonotliketheXMLlanguageyoucanalsousepureJavacodetodefinethesametest.InJavayouwouldalsomakeuseofthemessageendpointdefinitionandreferencethisinstance.ThesametestasshownaboveinJavaDSLlookslikethis:

JavaDSLdesigner

importorg.testng.ITestContext;importorg.testng.annotations.Test;importcom.consol.citrus.annotations.CitrusTest;importcom.consol.citrus.dsl.testng.TestNGCitrusTestDesigner;

@TestpublicclassSendMessageTestDesignerextendsTestNGCitrusTestDesigner

@CitrusTest(name="SendMessageTest")publicvoidsendMessageTest()description("Basicsendmessageexample");

send("helloServiceEndpoint").payload("<TestMessage>"+"<Text>Hello!</Text>"+"</TestMessage>").header("Operation","sayHello");

InsteadofusingtheXMLtagsforsendweusemethodsfromTestNGCitrusTestDesignerclass.Thesamemessageendpointisreferencedwithinthesendmessageaction.ThepayloadisconstructedasplainJavacharactersequencewhichisabitverbose.Wewillseelateronhowwecanimprovethis.Fornowitisimportanttounderstandthecombinationofsendtestactionandamessageendpoint.

CitrusReferenceGuide

58Endpoints

Page 59: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TipItisgoodpracticetofollownamingconventionswhendefiningnamesformessageendpoints.Theintendedpurposeofthemessageendpointaswellasthesending/receivingactorshouldbeclearwhenchoosingthename.ForinstancemessageEndpoint1,messageEndpoint2willnotgiveyoumuchhintstothepurposeofthemessageendpoint.

ThisisbasicallyhowtosendmessagesinCitrus.Thetestcaseisresponsibleforconstructingthemessagecontentwhilethepredefinedmessageendpointholdstransportspecificsettings.Testcasesreferenceendpointcomponentstopublishmessagestotheoutsideworld.Thisisjustthestartofaction.Citrussupportsawholepackageofotherwayshowtodefineandmanipulatethemessagecontents.Readmoreaboutmessagesendingactionsinactions-send.

Receivemessageswithendpoints

Nowwehavealookatthemessagereceivingpartinsidethetest.Asimpleexampleshowshowitworks.

XMLDSL

<receiveendpoint="helloServiceEndpoint"><message><payload><TestMessage><Text>Hello!</Text></TestMessage></payload></message><header><elementname="Operation"value="sayHello"/></header></receive>

Ifwerecapthesendactionofthepreviouschapterwecanidentifysomecommonmechanismsthatapplyforbothsendingandreceivingactions.Thetestactionalsousestheendpointattributeforreferencingapredefinedmessageendpoint.Thistimewewanttoreceiveamessagefromtheendpoint.AgainthetestisnotawareofthetransportdetailssuchasJMSconnections,endpointuri,andsoon.Themessageendpointcomponentencapsulatesthisinformation.

CitrusReferenceGuide

59Endpoints

Page 60: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

BeforewegointodetailonvalidatingthereceivedmessagewehaveaquicklookattheJavaDSLvariationforthereceiveaction.ThesamereceiveactionasabovelookslikethisinJavaDSL.

JavaDSLdesigner

@CitrusTestpublicvoidmessagingTest()receive("helloServiceEndpoint").payload("<TestMessage>"+"<Text>Hello!</Text>"+"</TestMessage>").header("Operation","sayHello");

Thereceiveactionwaitsforamessagetoarrive.Thewholetestexecutionisstoppedwhilewaitingforthemessage.Thisisimportanttoensurethestepbysteptestworkflowprocessing.Ofcourseyoucanspecifymessagetimeoutssothereceiverwillonlywaitagivenamountoftimebeforeraisingatimeouterror.Followingfromthattimeoutexceptionthetestcasefailsasthemessagedidnotarriveintime.Citrusdefinesdefaulttimeoutsettingsforallmessagereceivingtasks.

AtthispointyouknowthetwomostimportanttestactionsinCitrus.Sendingandreceivingactionswillbecomethemaincomponentsofyourintegrationtestswhendealingwithlooselycoupledmessagebasedcomponentsinaenterpriseapplicationenvironment.Itisveryeasytocreatecomplexmessageflows,meaningasequenceofsendingandreceivingactionsinyourtestcase.Youcanreplicateusecasesandtestyourmessageexchangewithextendedmessagevalidationcapabilities.Seeactions-receiveforamoredetaileddescriptiononhowtovalidateincomingmessagesandhowtoexpectmessagecontentsinatestcase.

Localmessagestore

Allmessagesthataresentandreceivedduringatestcasearestoredinalocalmemorystorage.Thisisbecausewemightwanttoaccessthemessagecontentlateroninatestcase.Wecandosobyusingmessagestorefunctionsforloadingmessagesthathavebeenexchangedearlierinthetest.WhenstoringamessageinthelocalstorageCitrususesamessagenameasidentifierkey.Thismessagenameislateronusedtoaccessthemessage.Youcandefinethemessagenameinanysendorreceiveaction:

XMLDSL

CitrusReferenceGuide

60Endpoints

Page 61: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<receiveendpoint="helloServiceEndpoint"><messagename="helloMessage"><payload><TestMessage><Text>Hello!</Text></TestMessage></payload></message><header><elementname="Operation"value="sayHello"/></header></receive>

JavaDSLdesigner

@CitrusTestpublicvoidmessagingTest()receive("helloServiceEndpoint").name("helloMessage").payload("<TestMessage>"+"<Text>Hello!</Text>"+"</TestMessage>").header("Operation","sayHello");

ThereceiveoperationabovesetthemessagenametohelloMessage.Themessagereceivedisautomaticallystoredinthelocalstoragewiththatname.Youcanaccessthemessagecontentforinstancebyusingafunction:

<echo><message>citrus:message(helloMessage.payload())</message></echo>

ThefunctionloadsthehelloMessageandprintsthepayloadinformationwiththeechotestaction.IncombinationwithXpathorJsonPathfunctionsthismechanismisagoodwaytoaccesstheexchangedmessagecontentslaterinatestcase.

NoteThestorageisforbothsentandreceivedmessagesinatestcase.Thestorageispertestcaseandcontainsallsentandreceivedmessages.

Whennoexplicitmessagenameisgiventhelocalstoragewillconstructadefaultmessagename.Thedefaultnameisbuiltfromtheaction(sendorreceive)plustheendpointusedtoexchangethemessage.Forinstance:

CitrusReferenceGuide

61Endpoints

Page 62: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

send(helloEndpoint)receive(helloEndpoint)

ThenamesabovewouldbegeneratedbyasendandreceiveoperationontheendpointnamedhelloEndpoint.

ImportantThemessagestoreisnotabletohandlemultiplemessageofthesamenameinonetestcase.Somessageswithidenticalnameswilloverwriteexistingmessagesinthelocalstorage.

NowwehaveseenthebasicendpointconceptinCitrus.Theendpointcomponentsrepresenttheconnectionstothetestboundarysystems.Thisishowwecanconnecttothesystemundertestformessageexchange.Andthisisourmaingoalwiththisintegrationtestframework.Wewanttoprovideeasyaccesstocommonmessagetransportsonclientandserversidesothatwecantestthecommunicationinterfacesonarealmessagetransportexchange.

CitrusReferenceGuide

62Endpoints

Page 63: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

MessagevalidationWhenCitrusreceivesamessagefromexternalapplicationsitistimetoverifythemessagecontent.Thismessagevalidationincludessyntaxrulesaswellassemanticvaluesthatneedtobecomparedtoanexpectedbehavior.Citrusprovidespowerfulmessagevalidationcapabilities.Eachincomingmessageisvalidatedwithsyntaxandsemantics.Thetesterisabletodefineexpectedmessageheadersandpayloads.Citrusmessagevalidatorimplementationswillcomparethemessagesandreportdifferencesastestfailure.WiththeupcomingsectionswehaveacloserlookatmessagevalidationofXMLmessageswithXPathandXMLschemavalidationandfurthermessageformatslikeJSONandplaintext.

JavaDSLvalidationcallbacks

TheJavaDSLofferssomeadditionalvalidationtricksandpossibilitieswhendealingwithmessagesthataresentandreceivedoverCitrus.Oneofthemisthevalidationcallbackfunctionality.Withthisfeatureyoucanmarshal/unmarshalmessagepayloadsandcodevalidationstepsonJavaobjects.

JavaDSLdesigner

@CitrusTestpublicvoidreceiveMessageTest()receive(bookResponseEndpoint).validationCallback(newMarshallingValidationCallback<AddBookResponseMessage>()@Overridepublicvoidvalidate(AddBookResponseMessageresponse,MessageHeadersheaders)Assert.isTrue(response.isSuccess()););

BydefaultthevalidationcallbackneedssomeXMLunmarshallerimplementationfortransformingtheXMLpayloadtoaJavaobject.CitruswillautomaticallysearchfortheunmarshallerbeaninyourSpringapplicationcontextifnothingspecificisset.Ofcourseyoucanalsosettheunmarshallerinstanceexplicitly.

JavaDSLdesigner

CitrusReferenceGuide

63Validation

Page 64: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

@AutowiredprivateUnmarshallerunmarshaller;

@CitrusTestpublicvoidreceiveMessageTest()receive(bookResponseEndpoint).validationCallback(newMarshallingValidationCallback<AddBookResponseMessage>(unmarshaller)@Overridepublicvoidvalidate(AddBookResponseMessageresponse,MessageHeadersheaders)Assert.isTrue(response.isSuccess()););

ObviouslyworkingonJavaobjectsismuchmorecomfortablethanusingtheXMLStringconcatenation.Thisiswhyyoucanalsousethisfeaturewhensendingmessages.

JavaDSLdesigner

@AutowiredprivateMarshallermarshaller;

@CitrusTestpublicvoidsendMessageTest()send(bookRequestEndpoint).payload(createAddBookRequestMessage("978-citrus:randomNumber(10)"),marshaller).header(SoapMessageHeaders.SOAP_ACTION,"addBook");

privateAddBookRequestMessagecreateAddBookRequestMessage(Stringisbn)AddBookRequestMessagerequestMessage=newAddBookRequestMessage();Bookbook=newBook();book.setAuthor("Foo");book.setTitle("FooTitle");book.setIsbn(isbn);book.setYear(2008);book.setRegistrationDate(Calendar.getInstance());requestMessage.setBook(book);returnrequestMessage;

TheexampleabovecreatesaAddBookRequestMessageobjectandputsthisaspayloadtoasendaction.IncombinationwithamarshallerinstanceCitrusisabletocreateaproperXMLmessagepayloadthen.

CitrusReferenceGuide

64Validation

Page 65: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Customizemessagevalidators

IntheprevioussectionswehavealreadyseensomeexamplesonhowtooverwritedefaultmessagevalidatorimplementationsinCitrus.BydefaultallmessagevalidatorscanbeoverwrittenbyplacingaSpringbeanofthesameidtotheSpringapplicationcontext.ThedefaultimplementationsofCitrusare:

defaultXmlMessageValidator:com.consol.citrus.validation.xml.DomXmlMessageValidatordefaultXpathMessageValidator:com.consol.citrus.validation.xml.XpathMessageValidatordefaultJsonMessageValidator:com.consol.citrus.validation.json.JsonTextMessageValidatordefaultJsonPathMessageValidator:com.consol.citrus.validation.json.JsonPathMessageValidatordefaultPlaintextMessageValidator:com.consol.citrus.validation.text.PlainTextMessageValidatordefaultMessageHeaderValidator:com.consol.citrus.validation.DefaultMessageHeaderValidatordefaultBinaryBase64MessageValidator:com.consol.citrus.validation.text.BinaryBase64MessageValidatordefaultGzipBinaryBase64MessageValidator:com.consol.citrus.validation.text.GzipBinaryBase64MessageValidatordefaultXhtmlMessageValidator:com.consol.citrus.validation.xhtml.XhtmlMessageValidatordefaultGroovyXmlMessageValidator:com.consol.citrus.validation.script.GroovyXmlMessageValidatordefaultGroovyTextMessageValidator:com.consol.citrus.validation.script.GroovyScriptMessageValidatordefaultGroovyJsonMessageValidator:com.consol.citrus.validation.script.GroovyJsonMessageValidator

Overwritingasinglemessagevalidatorwithacustomimplementationisthenveryeasy.JustaddyourcustomSpringbeantotheapplicationcontextusingoneofthesedefaultbeanidentifiers.IncaseyouwanttochangethemessagevalidatorgangbyaddingorremovingamessagevalidatorimplementationcompletelyyoucanplaceamessagevalidatorcomponentintheSpringapplicationcontext.

<citrus:message-validators><citrus:validatorref="defaultXmlMessageValidator"/>

CitrusReferenceGuide

65Validation

Page 66: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<citrus:validatorref="defaultXpathMessageValidator"/><citrus:validatorref="defaultGroovyXmlMessageValidator"/><citrus:validatorref="defaultPlaintextMessageValidator"/><citrus:validatorref="defaultMessageHeaderValidator"/><citrus:validatorref="defaultBinaryBase64MessageValidator"/><citrus:validatorref="defaultGzipBinaryBase64MessageValidator"/><citrus:validatorclass="com.consol.citrus.validation.custom.CustomMessageValidator"/><citrus:validatorref="defaultJsonMessageValidator"/><citrus:validatorref="defaultJsonPathMessageValidator"/><citrus:validatorref="defaultGroovyJsonMessageValidator"/><citrus:validatorref="defaultGroovyTextMessageValidator"/><citrus:validatorref="defaultXhtmlMessageValidator"/></citrus:message-validators>

ThelistingaboveaddsacustommessagevalidatorimplementationtothesequenceofmessagevalidatorsinCitrus.Wereferencedefaultmessagevalidatorsandaddaimplementationoftypecom.consol.citrus.validation.custom.CustomMessageValidator.Thecustomimplementationclasshastoimplementthebasicinterfacecom.consol.citrus.validation.MessageValidator.NowCitruswilltrytomatchthecustomimplementationtoincomingmessagetypesandoccasionallyexecutethemessagevalidatorlogic.ThisishowyoucanaddandchangethebasicmessagevalidatorregistryinCitrus.Youcanaddcustomimplementationsfornewmessageformatsveryeasy.

Thesameapproachappliesincaseyouwanttoremoveamessagevalidatorimplementationbybanningitcompletely.Justdeletetheentryinthemessagevalidatorregistrycomponent:

<citrus:message-validators><citrus:validatorref="defaultJsonMessageValidator"/><citrus:validatorref="defaultJsonPathMessageValidator"/><citrus:validatorref="defaultGroovyJsonMessageValidator"/><citrus:validatorref="defaultGroovyTextMessageValidator"/><citrus:validatorref="defaultMessageHeaderValidator"/></citrus:message-validators>

TheCitrusmessagevalidatorcomponentdeletedalldefaultimplementationsexceptofthosedealingwithJSONmessageformat.NowCitrusisonlyabletovalidateJSONmessages.BecarefulasthecompleteCitrusprojectwillbeaffectedbythischange.

CitrusReferenceGuide

66Validation

Page 67: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

XMLmessagevalidation

XMLisaverycommonmessageformatespeciallyintheSOAPWebServicesandJMSmessagingworld.CitrusprovidesXMLmessagevalidatorimplementationsthatareabletocompareXMLmessagestructures.ThevalidatorwillnoticedifferencesintheXMLmessagestructureandsupportsXMLnamespaces,attributesandXMLschemavalidation.ThedefaultXMLmessagevalidatorimplementationisactivebydefaultandcanbeoverwrittenwithacustomimplementationusingthebeaniddefaultXmlMessageValidator.

<beanid="defaultXmlMessageValidator"class="com.consol.citrus.validation.xml.DomXmlMessageValidator"

ThedefaultXMLmessagevalidatorisverypowerfulwhenitcomestocompareXMLstructures.Thevalidatorsupportsnamespaceswithdifferentprefixesandattributesalswellasnamespacequalifiedattributes.Seethefollowingsectionsforadetaileddescriptionofallcapabilities.

XMLpayloadvalidation

OnceCitrushasreceivedamessagethetestercanvalidatethemessagecontentsinvariousways.Firstofallthetestercancomparethewholemessagepayloadtoapredefinedcontrolmessagetemplate.

Thereceivingactionoffersfollowingelementsforcontrolmessagetemplates:

<payload>:DefinesthemessagepayloadasnestedXMLmessagetemplate.Thewholemessagepayloadisdefinedinsidethetestcase.

<data>:DefinesaninlineXMLmessagetemplateasnestedCDATA.SlightlydifferenttothepayloadvariationaswedefinethewholemessagepayloadinsidethetestcaseasCDATAsection.

<resource>:DefinesanexpectedXMLmessagetemplateviaexternalfileresources.Thistimethepayloadisloadedatruntimefromtheexternalfile.

Bothwaysinlinepayloaddefinitionorexternalfileresourcegiveusacontrolmessagetemplatethatthetestcaseexpectstoarrive.Citrususesthiscontroltemplateforextendedmessagecomparison.Allelements,namespaces,attributesandnodevalues

CitrusReferenceGuide

67Xml

Page 68: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

arevalidatedinthiscomparison.WhenusingXMLmessagepayloadsCitruswillnavigatethroughthewholeXMLstructurevalidatingeachelementanditscontent.SamewithJSONpayloads.

Onlyincasereceivedmessageandcontrolmessageareequaltoeachotherasexpectedthemessagevalidationwillpass.IncasedifferencesoccurCitrusgivesdetailederrormessagesandthetestcasefails.

Thecontrolmessagetemplateisnotnecessarilyverystatic.CitrussupportsvariouswaystoadddynamicmessagecontentontheonesideandontheothersideCitruscanignoresomeelementsthatarenotpartofmessagecomparison(e.g.whengeneratedcontentortimestampsarepartofthemessagecontent).Thetestercanenrichtheexpectedmessagetemplatewithtestvariablesorignoreexpressionssowegetamorerobustvalidationmechanism.Wewilltalkaboutthisinthenextsectionstocome.

WhenusingtheCitrusJavaDSLyouwillfaceaverbosemessagepayloaddefinition.ThisisbecauseJavadoesnotsupportmultilinecharactersequencevaluesasStrings.WehavetouseverboseStringconcatenationwhenconstructingXMLmessagepayloadcontentsforinstance.Inadditiontothatreservedcharacterslikequotesmustbeescapedandlinebreaksmustbeexplicitlyadded.AlltheseimpedimentsletmesuggesttouseexternalfileresourcesinJavaDSLwhendealingwithlargecomplexmessagepayloaddata.Hereisanexample:

JavaDSLdesigner

@CitrusTestpublicvoidreceiveMessageTest()receive("helloServiceServer").payload(newClassPathResource("com/consol/citrus/message/data/TestRequest.xml")).header("Operation","sayHello").header("MessageId","$messageId");

XMLheadervalidation

Nowthatwehavevalidatedthemessagepayloadinvariouswayswearenowinterestedinvalidatingthemessageheader.Thisissimpleasyouhavetodefinetheheadernameandthecontrolvaluethatyouexpect.Justaddthefollowingheadervalidationtoyourreceivingaction.

XMLDSL

CitrusReferenceGuide

68Xml

Page 69: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<header><elementname="Operation"value="GetCustomer"/><elementname="RequestTag"value="$requestTag"/></header>

JavaDSLdesigner

@CitrusTestpublicvoidreceiveMessageTest()receive("helloServiceServer").header("Operation","sayHello").header("MessageId","$messageId");

Messageheadersarerepresentedasname-valuepairs.Eachexpectedheaderelementidentifiedbyitsnamehastobepresentinthereceivedmessage.Inadditiontothattheheadervalueiscomparedtothegivencontrolvalue.IfaheaderentryisnotfoundbyitsnameorthevaluedoesnotfitaccordinglyCitruswillraisevalidationerrorsandthetestcasewillfail.

NoteSometimesmessageheadersmaynotapplytothename-valuepairpattern.ForexampleSOAPheaderscanalsocontainXMLfragments.Citrussupportsthesekindofheaderstoo.PleaseseetheSOAPchapterformoredetails.###IgnoreXMLelements

Someelementsinthemessagepayloadmightnotapplyforvalidationatall.Justthinkofcommunicationtimestampsandynamicvaluesinsideamessage:

Thetimestampvalueinournextexamplewilldynamicallychangefromtestruntotestrunandishardlypredictableforthetester,soletsignoreitinvalidation.

XMLDSL

<message><payload><TestMessage><MessageId>$messageId</MessageId><Timestamp>2001-12-17T09:30:47.0Z</Timestamp><VersionId>@ignore@</VersionId></TestMessage></payload><ignorepath="/TestMessage/Timestamp"/></message>

CitrusReferenceGuide

69Xml

Page 70: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

AlthoughwehavegivenastatictimestampvalueinthepayloaddatatheelementisignoredduringvalidationastheignoreXPathexpressionmatchestheelement.Inadditiontothatwealsoignoredtheversionidelementinthisexample.Thistimewithaninline@ignore@expression.ThisisforthoseofyouthatdonotlikeXPath.AsaresulttheignoredmessageelementsareautomaticallyskippedwhenCitruscomparesandvalidatesmessagecontentsanddonotbreakthetestcase.

WhenusingtheJavaDSLthe@ignore@placeholderaswellasXPathexpressionscanbeusedseamlessly.Hereisanexampleofthat:

JavaDSLdesigner

@CitrusTestpublicvoidreceiveMessageTest()receive("helloServiceServer").payload(newClassPathResource("com/consol/citrus/message/data/TestRequest.xml")).header("Operation","sayHello").header("MessageId","$messageId").ignore("/TestMessage/Timestamp");

Ofcourseyoucanusetheinline@ignore@placeholderinanexternalfileresource,too.

CustomizeXMLparserandserializer

WhenworkingwithXMLdataformatparsingandserializingisacommontask.XMLstructuresareparsedtoaDOM(DocumentObjectModel)representationinordertoprocesselements,attributesandtextnodes.AlsoDOMnodeobjectsgetserializedtoaStringmessagepayloadrepresentation.TheXMLparserandserializeriscustomizabletoacertainlevel.BydefaultCitrususestheDOMLevel3LoadandSaveimplementationwithfollowingsettings:

Parsersettings

cdata-sections=truesplit-cdata-sections=falsevalidate-if-schema=trueelement-content-whitespace=false

Serializersettings

format-pretty-print=truesplit-cdata-sections=false

CitrusReferenceGuide

70Xml

Page 71: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

element-content-whitespace=true

TheparametersarealsodescribedinW3CDOMconfigurationdocumentation.WecancustomizethedefaultsettingsbyaddingaXmlConfigurerSpringbeantotheCitrusapplicationcontext.

<beanid="xmlConfigurer"class="com.consol.citrus.xml.XmlConfigurer"><propertyname="parseSettings"><map><entrykey="validate-if-schema"value="false"value-type="java.lang.Boolean"/></map></property><propertyname="serializeSettings"><map><entrykey="comments"value="false"value-type="java.lang.Boolean"/><entrykey="format-pretty-print"value="false"value-type="java.lang.Boolean"/></map></property></bean>

NoteThisconfigurationisofglobalnature.AllXMLprocessingoperationswillbeaffectedwiththisconfiguration.

GroovyXMLvalidation

WiththeGroovyXmlSlurperyoucaneasilyvalidateXMLmessagepayloadswithouthavingtodealdirectlywithXML.PeoplewhodonotwanttodealwithXPathmayalsolikethisvalidationalternative.Thetesterdirectlynavigatesthroughthemessageelementsandusessimplecodeassertionsinordertocontrolthemessagecontent.HereisanexamplehowtovalidatemessageswithGroovyscript:

XMLDSL

<receiveendpoint="helloServiceClient"timeout="5000"><message><validate><scripttype="groovy">assertroot.children().size()==4assertroot.MessageId.text()=='$messageId'assertroot.CorrelationId.text()=='$correlationId'assertroot.User.text()=='HelloService'assertroot.Text.text()=='Hello'+context.getVariable("user")</script></validate>

CitrusReferenceGuide

71Xml

Page 72: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</message><header><elementname="Operation"value="sayHello"/><elementname="CorrelationId"value="$correlationId"/></header></receive>

JavaDSLdesigner

@CitrusTestpublicvoidreceiveMessageTest()receive("helloServiceClient").validateScript("assertroot.MessageId.text()=='$messageId';"+"assertroot.CorrelationId.text()=='$correlationId';").header("Operation,"sayHello").header("CorrelationId","$correlationId").timeout(5000L);

TheGroovyXmlSlurpervalidationscriptgoesrightintothemessage-taginsteadofaXMLcontroltemplateorXPathvalidation.TheGroovyscriptsupportsJavaassertstatementsformessageelementvalidation.Citrusautomaticallyinjectstherootelementroottothevalidationscript.ThisistheGroovyXmlSlurperobjectandthestartofelementnavigation.Basedonthisrootelementyoucanaccesschildelementsandattributeswithadotnotatedsyntax.Justusetheelementnamesseparatedbyasimpledot.Veryeasy!Ifyouneedthelistofchildelementsusethechildren()functiononanyelement.Withthetext()functionyougetaccesstotheelement'stext-value.Thesize()isveryusefulforvalidatingthenumberofchildelementswhichcompletesthebasicvalidationstatements.

Asyoucanseefromtheexample,wemayusetestvariableswithinthevalidationscript,too.Citrushasalsoinjectedtheactualtestcontexttothevalidationscript.Thetestcontextobjectholdsalltestvariables.Soyoucanalsoaccessvariableswithcontext.getVariable("user")forinstance.Onthetestcontextyoucanalsosetnewvariablevalueswithcontext.setVariable("user","newUserName").

Thereisevenmoreobjectinjectionforthevalidationscript.WiththeautomaticallyaddedobjectreceivedMessageYouhaveaccesstotheCitrusmessageobjectforthisreceiveaction.Thisenablesyoutodowhateveryouwantwiththemessagepayloadorheader.

XMLDSL

<receiveendpoint="helloServiceClient"timeout="5000">

CitrusReferenceGuide

72Xml

Page 73: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<message><validate><scripttype="groovy">assertreceivedMessage.getPayload(String.class).contains("HelloCitrus!")assertreceivedMessage.getHeader("Operation")=='sayHello'

context.setVariable("request_payload",receivedMessage.getPayload(String.class</script></validate></message></receive>

Thelistingaboveshowssomepowerofthevalidationscript.Wecanaccessthemessagepayload,wecanaccessthemessageheader.Withtestcontextaccesswecanalsosavethewholemessagepayloadasanewtestvariableforlaterusageinthetest.

IngeneralGroovycodeinsidetheXMLtestcasedefinitionoraspartoftheJavaDSLcodeisnotverycomfortabletomaintain.Youdonothavecodesyntaxassistorcodecompletion.Thisiswhywecanalsouseexternalfileresourcesforthevalidationscripts.Thesyntaxlookslikefollows:

XMLDSL

<receiveendpoint="helloServiceClient"timeout="5000"><message><validate><scripttype="groovy"file="classpath:validationScript.groovy"/></validate></message><header><elementname="Operation"value="sayHello"/><elementname="CorrelationId"value="$correlationId"/></header></receive>

JavaDSLdesigner

@CitrusTestpublicvoidreceiveMessageTest()receive("helloServiceClient").validateScript(newFileSystemResource("validationScript.groovy")).header("Operation,"sayHello").header("CorrelationId","$correlationId").timeout(5000L);

CitrusReferenceGuide

73Xml

Page 74: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

WereferencedsomeexternalfileresourcevalidationScript.groovy.Thisfilecontentisloadedatruntimeandisusedasscriptbody.NowthatwehaveanormalgroovyfilewecanusethecodecompletionandsyntaxhighlightingofourfavoriteGroovyeditor.

NoteYoucanusetheGroovyvalidationscriptincombinationwithothervalidationtypeslikeXMLtreecomparisonandXPathvalidation.TipForfurtherinformationontheGroovyXmlSlurperpleaseseetheofficialGroovywebsiteanddocumentation

CitrusReferenceGuide

74Xml

Page 75: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

XMLschemavalidation

ThereareseveralpossibilitiestodescribethestructureofXMLdocuments.ThetwomostpopularwaysareDTD(Documenttypedefinition)andXSD(XMLSchemadefinition).OnceaXMLdocumenthasdecidedtobeclassifiedusingaschemadefinitionthestructureofthedocumenthastofitthepredefinedrulesinsidetheschemadefinition.XMLdocumentinstancesarevalidonlyincasetheymeetallthesestructurerulesdefinedintheschemadefinition.CurrentlyCitruscanvalidateXMLdocumentsusingtheschemalanguagesDTDandXSD.

XSDschemarepositories

CitrustriestovalidateallincomingXMLmessagesagainstaschemadefinitioninordertoensurethatallrulesarefulfilled.AsaconsequencethemessagereceivingactionsinCitrusdohavetoknowtheXMLschemadefinition(*.xsd)fileresourcesthatbelongtoourproject.ThereforeCitrusintroducesacentralschemarepositorycomponentwhichholdsallavailableXMLschemafilesforaproject.

<citrus:schema-repositoryid="schemaRepository"><citrus:schemas><citrus:schemaid="travelAgencySchema"location="classpath:citrus/flightbooking/TravelAgencySchema.xsd"/><citrus:schemaid="royalArilineSchema"location="classpath:citrus/flightbooking/RoyalAirlineSchema.xsd"/><citrus:referenceschema="smartArilineSchema"/></citrus:schemas></citrus:schema-repository>

<citrus:schemaid="smartArilineSchema"location="classpath:citrus/flightbooking/SmartAirlineSchema.xsd"/>

AsyoucanseetheschemarepositoryisasimpleXMLcomponentdefinedinsidetheSpringapplicationcontext.Therepositorycanholdnestedschemadefinitionsdefinedbysomeidentifierandafilelocationforthexsdschemafile.Schemadefinitionscanalsobereferencedbyitsidentifierforusageinseveralschemarepositoryinstances.

ByconventionthedefaultschemarepositorycomponentisdefinedintheCitrusSpringapplicationcontextwiththeidschemaRepository.Springapplicationcontextisthenabletoinjecttheschemarepositoryintoallmessagereceivingtestactionsatruntime.ThereceivingtestactionconsolidatestherepositoryforamatchingschemadefinitionfileinordertovalidatetheincomingXMLdocumentstructure.

CitrusReferenceGuide

75Schema

Page 76: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TheconnectionbetweenincomingXMLmessagesandxsdschemafilesintherepositoryisdonebyamappingstrategywhichwewilldiscusslaterinthischapter.BydefaultCitruspickstherightschemabasedonthetargetnamespacethatisdefinedinsidetheschemadefinition.ThetargetnamespaceoftheschemadefinitionhastomatchthenamespaceoftherootelementinthereceivedXMLmessage.WiththismappingstrategyyouwillnothavetowireXMLmessagesandschemafilesmanuallyallisdoneautomaticallybytheCitrusschemarepositoryatruntime.AllyouneedtodoistoregisterallavailableschemadefinitionfilesregardlessofwhichtargetnamespaceornatureinsidetheCitrusschemarepository.

ImportantXMlschemavalidationismandatoryinCitrus.ThismeansthatCitrusalwaystriestofindamatchingschemadefinitioninsidetheschemarepositoryinordertoperformsyntaxvalidationonincomingschemaqualifiedXMLmessages.AclassifiedXMLmessageisdefinedbyitsnamespacedefinitions.Consequentlyyouwillgetvalidationerrorsincasenomatchingschemadefinitionfileisfoundinsidetheschemarepository.SoifyouexplicitlydonotwanttovalidatetheXMLschemaforsomereasonyouhavetodisablethevalidationexplicitlyinyourtestwithschema-validation="false".

<receiveendpoint="httpMessageEndpoint"><messageschema-validation="false"><validate><xpathexpression="//ns1:TestMessage/ns1:MessageHeader/ns1:MessageId"value="$messageId"/><xpathexpression="//ns1:TestMessage/ns1:MessageHeader/ns1:CorrelationId"value="$correlationId"/><namespaceprefix="ns1"value="http://citrus.com/namespace"/></validate></message><header><elementname="Operation"value="sayHello"/><elementname="MessageId"value="$messageId"/></header></receive>

ThismandatoryschemavalidationmightsoundannoyingtoyoubutinouropinionitisveryimportanttovalidatethestructureofthereceivedXMLmessages,sodisablingtheschemavalidationshouldnotbethestandardforalltests.Disablingautomaticschemavalidationshouldonlyapplytoveryspecialsituations.Sopleasetrytoputallavailableschemadefinitionstotheschemarepositoryandyouwillbefine.

WSDLschemas

CitrusReferenceGuide

76Schema

Page 77: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

InSOAPWebServicesworldtheWSDL(WebServiceSchemaDefinitionLanguage)definesthestructureannatureoftheXMLmessagesexchangedacrosstheinterface.OftentheWSDLfilesdoholdtheXMLschemadefinitionsasnestedelements.InCitrusyoucandirectlysettheWSDLfileaslocationofaschemadefinitionlikethis:

<citrus:schemaid="arilineWsdl"location="classpath:citrus/flightbooking/AirlineSchema.wsdl"/>

CitrusisabletofindthenestedschemadefinitionsinsidetheWSDLfileinordertobuildavalidschemafilefortheschemarepository.SoincomingXMLmessagesthatrefertotheWSDLfilecanbevalidatedforsyntaxrules.

Schemalocationpatterns

Settingallschemasonebyoneinaschemarepositorycanbeverboseanduncomfortable,especiallywhendealingwithlotsofxsdandwsdlfiles.Theschemarepositoryalsosupportslocationpatternexpressions.Seethisexampletoseehowitworks:

<citrus:schema-repositoryid="schemaRepository"><citrus:locations><citrus:locationpath="classpath:citrus/flightbooking/*.xsd"/></citrus:locations></citrus:schema-repository>

Theschemarepositorysearchesforallfilesmatchingtheresourcepathlocationpatternandaddsthemasschemainstancestotherepository.OfcoursethisalsoworkswithWSDLfiles.

Schemacollections

Sometimesmultipleaschemadefinitionisseparatedintomultiplefiles.ThisisaproblemfortheCitrusschemarepositoryastheschemamappingstrategythenisnotabletopicktherightfileforvalidation,inparticularwhenworkingwithtargetnamespacevaluesaskeyfortheschemamappingstrategy.Asasolutionforthisproblemyouhavetoputallschemaswiththesametargetnamespacevalueintoaschemacollection.

<citrus:schema-collectionid="flightbookingSchemaCollection"><citrus:schemas>

CitrusReferenceGuide

77Schema

Page 78: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<citrus:schemalocation="classpath:citrus/flightbooking/BaseTypes.xsd"/><citrus:schemalocation="classpath:citrus/flightbooking/AirlineSchema.xsd"/></citrus:schemas></citrus:schema-collection>

BothschemadefinitionsBaseTypes.xsdandAirlineSchema.xsdsharethesametargetnamespaceandthereforeneedtobecombinedinschemacollectioncomponent.Theschemacollectioncanbereferencedinanyschemarepositoryasnormalschemadefinition.

<citrus:schema-repositoryid="schemaRepository"><citrus:schemas><citrus:referenceschema="flightbookingSchemaCollection"/></citrus:schemas></citrus:schema-repository>

Schemamappingstrategy

TheschemarepositoryinCitrusholdsonetomanyschemadefinitionfilesanddynamicallypicksuptherightoneaccordingtothevalidatedmessagepayload.Therepositoryneedstohavesomestrategyfordecidingwhichschemadefinitiontochoose.Seethefollowingschemamappingstrategiesanddecidewhichofthemissuitableforyou.

TargetNamespaceMappingStrategy

Thisisthedefaultschemamappingstrategy.Schemadefinitionsusuallydefinesometargetnamespacewhichisvalidforallelementsandtypesinsidetheschemafile.ThetargetnamespaceisalsousedasrootnamespaceinXMLmessagepayloads.AccordingtothisinformationCitruscanpickuptherightschemadefinitionfileintheschemarepository.Youcansettheschemamappingstrategyaspropertyintheconfigurationfiles:

<citrus:schema-repositoryid="schemaRepository"schema-mapping-strategy="schemaMappingStrategy"><citrus:schemas><citrus:schemaid="helloSchema"location="classpath:citrus/samples/sayHello.xsd"/></citrus:schemas></citrus:schema-repository>

<beanid="schemaMappingStrategy"

CitrusReferenceGuide

78Schema

Page 79: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

class="com.consol.citrus.xml.schema.TargetNamespaceSchemaMappingStrategy"/>

ThesayHello.xsdschemafiledefinesatargetnamespace(http://consol.de/schemas/sayHello.xsd):

<xs:schemaxmlns:xs="http://www.w3.org/2001/XMLSchema"xmlns="http://consol.de/schemas/sayHello.xsd"targetNamespace="http://consol.de/schemas/sayHello.xsd"elementFormDefault="qualified"attributeFormDefault="unqualified">

</xs:schema>

IncomingrequestmessagesshouldalsohavethetargetnamespacesetintherootelementandthisishowCitrusmatchestherightschemafileintherepository.

<HelloRequestxmlns="http://consol.de/schemas/sayHello.xsd"><MessageId>123456789</MessageId><CorrelationId>1000</CorrelationId><User>Christoph</User><Text>HelloCitrus</Text></HelloRequest>

RootQNameMappingStrategy

ThenextpossibilityformappingincomingrequestmessagestoaschemadefinitionisviatheXMLrootelementQName.EachXMLmessagepayloadstartswitharootelementthatusuallydeclaresthetypeofaXMLmessage.Accordingtothisrootelementyoucansetupmappingsintheschemarepository.

<citrus:schema-repositoryid="schemaRepository"schema-mapping-strategy="schemaMappingStrategy"><citrus:schemas><citrus:referenceschema="helloSchema"/><citrus:referenceschema="goodbyeSchema"/></citrus:schemas></citrus:schema-repository>

<beanid="schemaMappingStrategy"class="com.consol.citrus.xml.schema.RootQNameSchemaMappingStrategy"><propertyname="mappings"><map><entrykey="HelloRequest"value="helloSchema"/><entrykey="GoodbyeRequest"value="goodbyeSchema"/>

CitrusReferenceGuide

79Schema

Page 80: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</map></property></bean>

<citrus:schemaid="helloSchema"location="classpath:citrus/samples/sayHello.xsd"/>

<citrus:schemaid="goodbyeSchema"location="classpath:citrus/samples/sayGoodbye.xsd"/>

Thelistingabovedefinestworootqnamemappings-oneforHelloRequestandoneforGoodbyeRequestmessagetypes.Anincomingmessageoftypeisthenmappedtotherespectiveschemaandsoon.WiththisdedicatedmappingsyouareabletocontrolwhichschemaisusedonaXMLrequest,regardlessoftargetnamespacedefinitions.

Schemamappingstrategychain

Let'sdiscussthepossibilitytocombineseveralschemamappingstrategiesinalogicalchain.Youcandefinemorethanonemappingstrategythatareevaluatedinsequence.Thefirststrategytofindaproperschemadefinitionfileintherepositorywins.

<citrus:schema-repositoryid="schemaRepository"schema-mapping-strategy="schemaMappingStrategy"><citrus:schemas><citrus:referenceschema="helloSchema"/><citrus:referenceschema="goodbyeSchema"/></citrus:schemas></citrus:schema-repository>

<beanid="schemaMappingStrategy"class="com.consol.citrus.xml.schema.SchemaMappingStrategyChain"><propertyname="strategies"><list><beanclass="com.consol.citrus.xml.schema.RootQNameSchemaMappingStrategy"><propertyname="mappings"><map><entrykey="HelloRequest"value="helloSchema"/></map></property></bean><beanclass="com.consol.citrus.xml.schema.TargetNamespaceSchemaMappingStrategy"/></list></property></bean>

CitrusReferenceGuide

80Schema

Page 81: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

SotheschemamappingchainusesbothRootQNameSchemaMappingStrategyandTargetNamespaceSchemaMappingStrategyincombination.Incasethefirstrootqnamestrategyfailstofindapropermappingthenexttargetnamespacestrategycomesinandtriestofindaproperschema.

Schemadefinitionoverruling

Nowitistimetotalkaboutschemadefinitionsettingsontestactionlevel.WehavelearnedbeforethatCitrustriestoautomaticallyfindamatchingschemadefinitioninsomeschemarepository.Therecomesatimewhereyouasatesterjusthavetopicktherightschemadefinitionbyyourself.YoucanoverruleallschemamappingstrategiesinCitrusbydirectlysettingthedesiredschemainyourreceivingmessageaction.

<receiveendpoint="httpMessageEndpoint"><messageschema="helloSchema"><validate><xpathexpression="//ns1:TestMessage/ns1:MessageHeader/ns1:MessageId"value="$messageId"/><xpathexpression="//ns1:TestMessage/ns1:MessageHeader/ns1:CorrelationId"value="$correlationId"/><namespaceprefix="ns1"value="http://citrus.com/namespace"/></validate></message></receive>

<citrus:schemaid="helloSchema"location="classpath:citrus/samples/sayHello.xsd"/>

Intheexampleabovethetesterexplicitlysetsaschemadefinitioninthereceiveaction(schema="helloSchema").Theattributevaluereferstonamedschemabeansomewhereintheapplciationcontext.Thisoverrulesallschemamappingstrategiesusedinthecentralschemarepositoryasthegivenschemaisdirectlyusedforvalidation.Thisfeatureishelpfulwhendealingwithdifferentschemaversionsatthesametimewheretheschemarepositorycannothelpyouanymore.

Anotherpossibilitywouldbetosetacustomschemarepositoryatthispoint.ThismeansyoucanhavemorethanoneschemarepositoryinyourCitrusprojectandyoupicktherightonebyyourselfinthereceiveaction.

<receiveendpoint="httpMessageEndpoint"><messageschema-repository="mySpecialSchemaRepository"><validate><xpathexpression="//ns1:TestMessage/ns1:MessageHeader/ns1:MessageId"

CitrusReferenceGuide

81Schema

Page 82: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

value="$messageId"/><xpathexpression="//ns1:TestMessage/ns1:MessageHeader/ns1:CorrelationId"value="$correlationId"/><namespaceprefix="ns1"value="http://citrus.com/namespace"/></validate></message></receive>

Theschema-repositoryattributereferstoaCitrusschemarepositorycomponentwhichisdefinedsomewhereintheSpringapplicationcontext.

ImportantIncaseyouhaveseveralschemarepositoriesinyourprojectdoalwaysdefineadefaultrepository(name="schemaRepository").ThishelpsCitrustoalwaysfindatleastonerepositorytointeractwith.

DTDvalidation

XMLDTD(Documenttypedefinition)isanotherwaytovalidatethestructureofaXMLdocument.ManypeoplesaythatDTDisdeprecatedandXMLschemaisthemuchmoreefficientwaytodescribetherulesofaXMLstructure.Wedonotdisagreewiththat,butwealsoknowthatlegacysystemsmightstilluseDTD.SoinordertoavoidvalidationerrorswehavetodealwithDTDvalidationaswell.

FirstthingyoucandoaboutDTDvalidationistospecifyaninlineDTDinyourexpectedmessagetemplate.

<receiveendpoint="httpMessageEndpoint"><messageschema-validation="false"><data><![CDATA[<!DOCTYPEroot[<!ELEMENTroot(message)><!ELEMENTmessage(text)><!ELEMENTtext(#PCDATA)>]><root><message><text>HelloTestFramework!</text></message></root>]]><data/></message></receive>

CitrusReferenceGuide

82Schema

Page 83: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ThesystemundertestmayalsosendthemessagewithainlineDTDdefinition.Sovalidationwillsucceed.

InmostcasestheDTDisreferencedasexternal.dtdfileresource.Youcandothisinyourexpectedmessagetemplateaswell.

<receiveendpoint="httpMessageEndpoint"><messageschema-validation="false"><data><![CDATA[<!DOCTYPErootSYSTEM"com/consol/citrus/validation/example.dtd"><root><message><text>HelloTestFramework!</text></message></root>]]><data/></message></receive>

CitrusReferenceGuide

83Schema

Page 84: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

JSONmessagevalidation

MessageformatssuchasJSONhavebecomeverypopular,inparticularwhenspeakingofRESTfulWebServicesandJavaScriptusingJSONasthemessageformattogofor.CitrusisabletoexpectandvalidateJSONmessagesaswewillseeinthenextsections.

ImportantBydefaultCitruswilluseXMLmessageformatswhensendingandreceivingmessages.ThisalsoreflectstothemessagevalidationlogicCitrususesforincomingmessages.SobydefaultCitruswilltrytoparsetheincomingmessageasXMLDOMelementtree.IncasewewouldliketoenableJSONmessagevalidationwehavetotellCitrusthatweexpectaJSONmessagerightnow.

Andthisisquiteeasy.CitrushasaJSONmessagevalidatorimplementationactivebydefaultandimmediatelyaswemarkanincomingmessageasJSONdatathismessagevalidatorwilljumpin.

CitrusprovidesseveraldefaultmessagevalidatorimplementationsforJOSNmessageformat:

com.consol.citrus.validation.json.JsonTextMessageValidator:BasicJSONmessagevalidatorimplementationcomparesJSONobjects(expectedandreceived).TheorderofJSONentriescandifferasspecifiedinJSONprotocol.TesterdefinesanexpectedcontrolJSONobjectwithtestvariablesandignoredentries.JSONArrayaswellasnestedJSONObjectsaresupported,too.TheJSONvalidatorofferstwodifferentmodestooperate.Bydefaultstrictmodeissetandthevalidatorwillalsochecktheexactamountofcontrolobjectfieldstomatch.NoadditionalfieldsinreceivedJSONdatastructurewillbeaccepted.InsoftmodevalidatorallowsadditionalfieldsinreceivedJSONdatastructuresothecontrolJSONobjectcanbeapartialsubsetinwhichcaseonlythecontrolfieldsarevalidated.AdditionalfieldsinthereceivedJSONdatastructureareignoredthen.

com.consol.citrus.validation.script.GroovyJsonMessageValidator:ExtendedgroovymessagevalidatorprovidesspecificJSONslurpersupport.WithJSONslurperthetestercanvalidatetheJSONmessagepayloadwithclosuresforinstance.

YoucanoverwritethisdefaultmessagevalidatorsforJSONbyplacingabeanintotheSpringApplicationcontext.Thebeanusesadefaultnameasidentifier.Thenyourcustombeanwilloverwritethedefaultvalidator:

<beanid="defaultJsonMessageValidator"class="com.consol.citrus.validation.json.JsonTextMessageValidator"

CitrusReferenceGuide

84Json

Page 85: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<beanid="defaultGroovyJsonMessageValidator"class="com.consol.citrus.validation.script.GroovyJsonMessageValidator"

ThisishowyoucancustomizethemessagevalidatorsusedforJSONmessagedata.

WehavementionedbeforethatCitrusisworkingwithXMLbydefault.ThisiswhywehavetotellCitrusthatthemessagethatwearereceivingusestheJSONmessageformat.WehavetotellthetestcasereceivingactionthatweexpectadifferentformatotherthanXML.

<receiveendpoint="httpMessageEndpoint"><messagetype="json"><data>"type":"read","mbean":"java.lang:type=Memory","attribute":"HeapMemoryUsage","path":"@equalsIgnoreCase('USED')@","value":"$heapUsage","timestamp":"@ignore@"</data></message></receive>

Themessagereceivingactioninourtestcasespecifiesamessageformattypetype="json".ThistellsCitrustolookforsomemessagevalidatorimplementationcapableofvalidatingJSONmessages.AswehaveaddedthepropermessagevalidatortotheSpringapplicationcontextCitruswillpicktherightvalidatorandJSONmessagevalidationisperformedonthismessage.Asyoucanseeyouwecanusetheusualtestvariablesandtheignoreelementsyntaxhere,too.CitrusisabletohandledifferentJSONelementorderswhencomparingreceivedandexpectedJSONobject.WecanalsouseJSONarraysandnestedobjects.ThedefaultJSONmessagevalidatorimplementationinCitrusisverypowerfulincomparingJSONobjects.

InsteadofdefininganexpectedmessagepayloadtemplatewecanalsouseGroovyvalidationscripts.LetshavealookattheGroovyJSONmessagevalidatorexample.AsusualthedefaultGroovyJSONmessagevalidatorisactivebydefault.ButthespecialGroovymessagevalidatorimplementationwillonlyjumpinwhenweusedavalidationscriptinourreceivemessagedefinition.Let'shaveanexampleforthat.

CitrusReferenceGuide

85Json

Page 86: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<receiveendpoint="httpMessageEndpoint"><messagetype="json"><validate><scripttype="groovy">

</script></validate></message></receive>

AgainwetellCitrusthatweexpectamessageoftype="json".NowweusedavalidationscriptthatiswritteninGroovy.CitruswillautomaticallyactivatethespecialmessagevalidatorthatexecutesourGroovyscript.ThescriptvalidationismorepowerfulaswecanusethefullpoweroftheGroovylanguage.ThevalidationscriptautomaticallyhasaccesstotheincomingJSONmessageobjectjson.WecanusetheGroovyJSONdotnotatedsyntaxinordertonavigatethroughtheJSONstructure.TheGroovyJSONslurperobjectjsonisautomaticallypassedtothevalidationscript.ThiswayyoucanaccesstheJSONobjectelementsinyourcodedoingsomeassertions.

Thereisevenmoreobjectinjectionforthevalidationscript.WiththeautomaticallyaddedobjectreceivedMessageYouhaveaccesstotheCitrusmessageobjectforthisreceiveaction.Thisenablesyoutodowhateveryouwantwiththemessagepayloadorheader.

XMLDSL

<receiveendpoint="httpMessageEndpoint"><messagetype="json"><validate><scripttype="groovy">assertreceivedMessage.getPayload(String.class).contains("HelloCitrus!")assertreceivedMessage.getHeader("Operation")=='sayHello'

context.setVariable("request_payload",receivedMessage.getPayload(String.class</script></validate></message></receive>

CitrusReferenceGuide

86Json

Page 87: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Thelistingaboveshowssomepowerofthevalidationscript.Wecanaccessthemessagepayload,wecanaccessthemessageheader.Withtestcontextaccesswecanalsosavethewholemessagepayloadasanewtestvariableforlaterusageinthetest.

IngeneralGroovycodeinsidetheXMLtestcasedefinitionoraspartoftheJavaDSLcodeisnotverycomfortabletomaintain.Youdonothavecodesyntaxassistorcodecompletion.Thisiswhywecanalsouseexternalfileresourcesforthevalidationscripts.Thesyntaxlookslikefollows:

XMLDSL

<receiveendpoint="helloServiceClient"timeout="5000"><message><validate><scripttype="groovy"file="classpath:validationScript.groovy"/></validate></message></receive>

JavaDSLdesigner

@CitrusTestpublicvoidreceiveMessageTest()receive("helloServiceClient").validateScript(newFileSystemResource("validationScript.groovy"));

WereferencedsomeexternalfileresourcevalidationScript.groovy.Thisfilecontentisloadedatruntimeandisusedasscriptbody.NowthatwehaveanormalgroovyfilewecanusethecodecompletionandsyntaxhighlightingofourfavoriteGroovyeditor.

ImportantUsingseveralmessagevalidatorimplementationsatthesametimeintheSpringapplicationcontextisalsonoproblem.Citrusautomaticallysearchesforallavailablemessagevalidatorsapplicableforthegivenmessageformatandexecutesthesevalidatorsinsequence.SoseveralmessagevalidatorscancoexistinaCitrusproject.

WhenwehavemultiplemessagevalidatorsthatapplytothemessageformatCitruswillexecutealloftheminsequence.Incaseyouneedtoexplicitlychooseamessagevalidatorimplementationyoucandosointhereceiveaction:

<receiveendpoint="httpMessageEndpoint"><messagetype="json"validator="groovyJsonMessageValidator">

CitrusReferenceGuide

87Json

Page 88: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<validate><scripttype="groovy">

</script></validate></message></receive>

InthisexampleweusethegroovyJsonMessageValidatorexplicitlyinthereceivetestaction.ThemessagevalidatorimplementationwasaddedasSpringbeanwithidgroovyJsonMessageValidatortotheSpringapplicationcontextbefore.NowCitruswillonlyexecutetheexplicitmessagevalidator.Otherimplementationsthatmightalsoapplyareskipped.

TipBydefaultCitruswillconsolidateallavailablemessagevalidatorsforamessageformatinsequence.Youcanexplicitlypickaspecialmessagevalidatorinthereceivemessageactionasshownintheexampleabove.Inthiscaseallothervalidatorswillnottakepartinthisspecialmessagevalidation.Butbecareful:Whenpickingamessagevalidatorexplicitlyyouareofcourselimitedtothismessagevalidatorcapabilities.Validationfeaturesofothervalidatorsarenotvalidinthiscase(e.g.messageheadervalidation,XPathvalidation,etc.)

SomuchforreceivingJSONmessagedatainCitrus.OfcoursesendingJSONmessagesinCitrusisalsoveryeasy.JustuseJSONmessagepayloadsinyoursendingmessageaction.

<sendendpoint="httpMessageEndpoint"><message><data>"type":"read","mbean":"java.lang:type=Memory","attribute":"HeapMemoryUsage","path":"used"</data></message></send>

CitrusReferenceGuide

88Json

Page 89: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

CitrusReferenceGuide

89Json

Page 90: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

XHTMLmessagevalidation

WhenCitrusreceivesplainHtmlmessageswelikelywanttousethepowerfulXMLvalidationcapabilitiessuchasXMLtreecomparisonorXPathsupport.UnfortunatelyHtmlmessagesdonotfollowtheXMLwellformedrulesverystrictly.ThisimpliesthatXMLmessagevalidationwillfailbecauseofnonwellformedHtmlcode.

XHTMLclosesthisgapbyautomaticallyfixingthemostcommonHtmlXMLincompatibleruleviolationssuchasmissingendtags(e.g.).

Let'strythiswithasimpleexample.Veryfirstthingforustodoistoaddanewlibrarydependencytotheproject.CitrusisusingthejtidylibraryinordertopreparetheHTMLandXHTMLmessagesforvalidation.Asthis3rdpartydependencyisoptionalinCitruswehavetoadditnowtoourprojectdependencylist.JustaddthejtidydependencytoyourMavenprojectPOM.

<dependency><groupId>net.sf.jtidy</groupId><artifactId>jtidy</artifactId><version>r938</version></dependency>

Pleaserefertothejtidyprojectdocumentationforthelatestversions.Noweverythingisready.AsusualtheCitrusmessagevalidatorforXHTMLisactiveinbackgroundbydefault.YoucanoverwritethisdefaultimplementationbyplacingaSpringbeanwithiddefaultXhtmlMessageValidatortotheCitrusapplicationcontext.

<beanid="defaultXhtmlMessageValidator"class="com.consol.citrus.validation.xhtml.XhtmlMessageValidator"

NowwecantellthetestcasereceivingactionthatwewanttousetheXHTMLmessagevalidationinourtestcase.

<receiveendpoint="httpMessageEndpoint"><messagetype="xhtml"><data><![CDATA[<!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.1//EN""org/w3c/xhtml/xhtml1-strict.dtd"><htmlxmlns="http://www.w3.org/1999/xhtml"><head>

CitrusReferenceGuide

90Xhtml

Page 91: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<title>CitrusHelloWorld</title></head><body><h1>HelloWorld!</h1><br/><p>Thisisatest!</p></body>]]></data></message></receive>

Themessagereceivingactioninourtestcasehastospecifyamessageformattypetype="xhtml".AsyoucanseetheHtmlmessagepayloadgetXHTMLspecificDOCTYPEprocessinginstruction.Thexhtml1-strict.dtdismandatoryintheXHTMLmessagevalidation.ForbetterconvenienceallXHTMLdtdfilesarepackagedwithinCitrussoyoucanusethisasarelativepath.

TheincomingHtmlmessageisautomaticallyconvertedintoproperXHTMLcodewithwellformedXML.SonowtheXHTMLmessagevalidatorcanusetheXMLmessagevalidationmechanismofCitrusforcomparingreceivedandexpecteddata.Asusualyoucanusetestvariables,ignoreelementexpressionsandXPathexpressions.

CitrusReferenceGuide

91Xhtml

Page 92: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Plaintextmessagevalidation

PlaintextmessagevalidationistheeasiestvalidationinCitrusthatyoucanthinkof.ThisvalidationjustperformsanexactJavaStringmatchofreceivedandexpectedmessagepayloads.

Asusualadefaultmessagevalidatorforplaintextmessagesisactivebydefault.Citruswillpickthismessagevalidatorforallmessagesoftype="plaintext".ThedefaultmessagevalidatorimplementationcanbeoverwrittenbyplacingaSpringbeanwithiddefaultPlaintextMessageValidatortotheSpringapplicationcontext.

<beanid="defaultPlaintextMessageValidator"class="com.consol.citrus.validation.text.PlainTextMessageValidator"

InthetestcasereceivingactionwetellCitrustouseplaintextmessagevalidation.

<receiveendpoint="httpMessageEndpoint"><messagetype="plaintext"><data>HelloWorld!</data></message></receive>

Withthemessageformattypetype="plaintext"setCitrusperformsStringequalsonthemessagepayloads(receivedandexpected).Onlyexactmatchwillpassthetest.

BythewaysendingplaintextmessagesinCitrusisalsoveryeasy.Justusetheplaintextmessagepayloaddatainyoursendingmessageaction.

<sendendpoint="httpMessageEndpoint"><message><data>HelloWorld!</data></message></send>

Ofcoursetestvariablesaresupportedintheplaintextpayloads.Thevariablesarereplacebythereferencedvaluesbeforesendingorreceivingthemessage.

Plaintextmessagepayloadsmayonlydifferinwhitespacese.g.newlinecharacters.Bydefaultthemessagevalidationfailsevenifonlywhitespacecharactersaredifferent.

CitrusReferenceGuide

92Plaintext

Page 93: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Youcandisablethisdefaultbehaviorandignorewhitespacescharacterslikenewlineswithfollowingsystemproperty:

citrus.plaintext.validation.ignore.whitespace=true

Alsoyoucouldsetthepropertydirectlyonthemesagevalidatorbean:

<beanid="defaultPlaintextMessageValidator"class="com.consol.citrus.validation.text.PlainTextMessageValidator"<propertyname="ignoreWhitespace"value="true"/></bean>

CitrusReferenceGuide

93Plaintext

Page 94: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Binarymessagevalidation

Binarymessagevalidationisnotveryeasytodoespeciallywhenitcomestocomparedatawithagivencontrolmessage.Asatesteryouwanttovalidatethebinarycontent.InCitrusthewaytocomparebinarymessagecontentistousebase64Stringencoding.Thebinarydataisencodedasbase64charactersequenceandthereforeiscomparablewithanexpectedcontent.

Thereceivedmessagecontentdoesnothavetobebase64encoded.Citrusisdoingthisconversionautomaticallybeforevalidationtakesplace.Thebinarydatacanbeanythinge.g.images,pdforgzipcontent.

Thedefaultmessagevalidatorforbinarymessagesisactivebydefault.Citruswillpickthismessagevalidatorforallmessagesoftype="binary_base64".ThedefaultmessagevalidatorimplementationcanbeoverwrittenbyplacingaSpringbeanwithiddefaultBinaryBase64MessageValidatortotheSpringapplicationcontext.

<beanid="defaultBinaryBase64MessageValidator"class="com.consol.citrus.validation.text.BinaryBase64MessageValidator"

InthetestcasereceivingactionwetellCitrustousebinarybase64messagevalidation.

<receiveendpoint="httpMessageEndpoint"><messagetype="binary_base64"><data>citrus:encodeBase64('HelloWorld!')</data></message></receive>

Withthemessageformattypetype="binary_base64"Citrusperformsthebase64charactersequencevalidation.Incomingmessagecontentisautomaticallyencodedasbase64Stringandcomparedtotheexpecteddata.Thiswaywecanmakesurethatthebinarycontentisasexpected.

BythewaysendingbinarymessagesinCitrusisalsoveryeasy.Justusethetype="binary"messagetypeinthesendoperation.Citrusnowconvertsthemessagepayloadtoabinarystreamaspayload.

<sendendpoint="httpMessageEndpoint"><messagetype="binary"><data>HelloWorld!</data></message>

CitrusReferenceGuide

94Binary

Page 95: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</send>

Base64encodingisalsosupportedinoutboundmessages.JustusetheencodeBase64functioninCitrus.Theresultisabase64encodedStringasmessagepayload.

<sendendpoint="httpMessageEndpoint"><message><data>citrus:encodeBase64('HelloWorld!')</data></message></send>

CitrusReferenceGuide

95Binary

Page 96: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Gzipmessagevalidation

Gzipisafamousmessagecompressionlibrary.Whendealingwithlargemessagecontentthecompressionmightbeagoodwaytooptimizethemessagetransportation.Citrusisabletohandlegzippedmessagepayloadsonsendandreceiveoperations.Whensendingcompresseddatawejusthavetousethemessagetypegzip.

<sendendpoint="messageEndpoint"><messagetype="gzip"><data>HelloWorld!</data></message></send>

Justusethetype="gzip"messagetypeinthesendoperation.Citrusnowconvertsthemessagepayloadtoagzipbinarystreamaspayload.

Whenvalidatinggzipbinarymessagecontentthemessagesarecomparedwithagivencontrolmessageinbinarybase64Stringrepresentation.Thegzipbinarydataisautomaticallyunzippedandencodedasbase64charactersequenceinordertocomparewithanexpectedcontent.

Thereceivedmessagecontentisusinggzipformatbuttheactualmessagecontentdoesnothavetobebase64encoded.Citrusisdoingthisconversionautomaticallybeforevalidationtakesplace.Thebinarydatacanbeanythinge.g.images,pdforplaintextcontent.

Thedefaultmessagevalidatorforgzipmessagesisactivebydefault.Citruswillpickthismessagevalidatorforallmessagesoftype="gzip_base64".ThedefaultmessagevalidatorimplementationcanbeoverwrittenbyplacingaSpringbeanwithiddefaultGzipBinaryBase64MessageValidatortotheSpringapplicationcontext.

<beanid="defaultGzipBinaryBase64MessageValidator"class="com.consol.citrus.validation.text.GzipBinaryBase64MessageValidator"

InthetestcasereceivingactionwetellCitrustousegzipmessagevalidation.

<receiveendpoint="messageEndpoint"><messagetype="gzip_base64"><data>citrus:encodeBase64('HelloWorld!')</data></message></receive>

CitrusReferenceGuide

96Gzip

Page 97: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Withthemessageformattypetype="gzip_base64"Citrusperformsthegzipbase64charactersequencevalidation.Incomingmessagecontentisautomaticallyunzippedandencodedasbase64Stringandcomparedtotheexpecteddata.Thiswaywecanmakesurethatthebinarycontentisasexpected.

NoteIfyouareusinghttpclientandservercomponentsthegzipcompressionsupportisbuiltinwiththeunderlyingSpringandhttpcommonslibraries.SoinhttpcommunicationyoujusthavetosettheheaderAccept-Encoding=gziporContent-Encoding=gzip.Themessagedataisthenautomaticallyzipped/unzippedbeforeCitrusgetsthemessagedataforvalidation.Readmoreaboutthishttpspecificgzipcompressioninchapterhttp.

CitrusReferenceGuide

97Gzip

Page 98: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

UsingXPathSometimeagointhisdocumentwehavealreadyseenhowXMLmessagepayloadsareconstructedwhensendingandreceivingmessages.NowusingXPathisaverypowerfulwayofaccessingelementsincomplexXMLstructures.TheXPathexpressionlanguageisveryhandywhenitcomestosaveelementvaluesastestvariablesorwhenvalidatingspecialelementsinaXMLmessagestructure.

XPathisaverypowerfultechnologyforwalkingXMLtrees.ThisW3CstandardstandsforadvancedXMLtreehandlingusingaspecialsyntaxasquerylanguage.CitrussupportstheXPathsyntaxinthefollowingfields:

<message><elementpath="[XPath-Expression]"></message><validate><xpathexpression="[XPath-Expression]"/></validate><extract><messagepath="[XPath-Expression]"></extract><ignorepath="[XPath-Expression]"/>

ThenextprogramlistingindicatesthepowerinusingXPathwithCitrus:

<message><validate><xpathexpression="//User/Name"value="John"/><xpathexpression="//User/Address[@type='office']/Street"value="Companystreet21"/><xpathexpression="//User/Name"value="$userName"/><xpathexpression="//User/@isAdmin"value="$isAdmin"/><xpathexpression="//User/@isAdmin"value="true"result-type="boolean"/><xpathexpression="//*[.='search-for']"value="searched-for"/><xpathexpression="count(//orderStatus[.='success'])"value="3"result-type="number"/></validate></message>

NowwedescribetheXPathusageinCitrusstepbystep.

ManipulatewithXPath

SomeelementsinXMLmessagepayloadsmightbeofdynamicnature.Justthinkofgeneratedidentifiersortimestamps.Alsowedonotwanttorepeatthesamestaticidentifierseveraltimesinourtestcases.Thisisthetimewheretestvariablesanddynamicmessageelementoverwritecomeinhandy.Theideaissimple.Wewantto

CitrusReferenceGuide

98Xpath

Page 99: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

overwriteaspecificmessageelementinourpayloadwithadynamicvalue.ThiscanbedonewithXPathorinlinevariabledeclarations.Letshavealookatanexamplelistingshowingbothways:

XMLDSL

<message><payload><TestMessage><MessageId>$messageId</MessageId><CreatedBy>_</CreatedBy><VersionId>$version</VersionId></TestMessage></payload><elementpath="/TestMessage/CreatedBy"value="$user"/></message>

Theprogramlistingaboveshowswaysofsettingvariablevaluesinsideamessagetemplate.Firstofallyoucansimplyplacevariableexpressionsinsidethemessage(seehow$messageIdisused).InadditiontothatyoucanalsouseXPathexpressionstoexplicitlyoverwritemessageelementsbeforevalidation.

<elementpath="/TestMessage/CreatedBy"value="$user"/>

TheXPathexpressionevaluatesandsearchesfortherightelementinthemessagepayload.Thepreviouslydefinedvariable$userreplacestheelementvalue.OfcoursethisworkswithXMLattributestoo.

BothwaysviaXPathorinlinevariableexpressionsareequaltoeachother.WithrespecttothecomplexityofXMLnamespacesandXPathyoumayfindtheinlinevariableexpressionmorecomfortabletouse.Anywayfeelfreetochoosethewaythatfitsbestforyou.Thisishowwecanadddynamicvariablevaluestothecontroltemplateinordertoincreasemaintainabilityandrobustnessofmessagevalidation.

TipValidationmatchersputvalidationmechanismstoanewlevelofferingdynamicassertionstatementsforvalidation.Havealookatthepossibilitieswithassertionstatementsinvalidation-matchers###ValidatewithXPath

WehavealreadyseenhowtovalidatewholeXMLstructureswithcontrolmessagetemplates.Allelementsarevalidatedandcomparedoneafteranother.Insomecasesthisapproachmightbetooextensive.Imaginethetesteronlyneedstovalidateasmall

CitrusReferenceGuide

99Xpath

Page 100: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

subsetofmessageelements.Thedefinitionofcontroltemplatesincombinationwithseveralignorestatementsisnotappropriateinthiscase.Youwouldratherwanttouseexplicitelementvalidation.

XMLDSL

<message><validate><xpathexpression="/TestRequest/MessageId"value="$messageId"/><xpathexpression="/TestRequest/VersionId"value="2"/></validate></message>

JavaDSLdesigner

@CitrusTestpublicvoidreceiveMessageTest()receive("helloServiceServer").validate("/TestRequest/MessageId","$messageId").validate("//VersionId","2").header("Operation","sayHello");

InsteadofcomparingthewholemessagesomemessageelementsarevalidatedexplicitlyviaXPath.CitrusevaluatestheXPathexpressiononthereceivedmessageandcomparestheresultvaluetothecontrolvalue.Thebasicmessagestructureaswellasallothermessageelementsarenotincludedintothisexplicitvalidation.

NoteIfthistypeofelementvalidationischosenneithernornortemplatedefinitionsareallowedinCitrusXMLtestcases.

TipCitrusoffersanalternativedot-notatedsyntaxinordertowalkthroughXMLtrees.IncaseyouarenotfamiliarwithXPathorsimplyneedaveryeasywaytofindyourelementinsidetheXMLtreeyoumightusethisway.EveryelementhierarchyintheXMLtreeisrepresentedwithasimpledot-forexample:

TestRequest.VersionId

TheexpressionwillsearchtheXMLtreefortherespectiveelement.Attributesaresupportedtoo.Incasethelastelementinthedot-notatedexpressionisaXMLattributetheframeworkwillautomaticallyfindit.

CitrusReferenceGuide

100Xpath

Page 101: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Ofcoursethisdot-notatedsyntaxisverysimpleandmightnotbeapplicableformorecomplextreenavigation.XPathismuchmorepowerful-nodoubt.Howeverthedot-notatedsyntaxmighthelpthoseofyouthatarenotfamiliarwithXPath.Sothedot-notationissupportedwhereverXPathexpressionsmightapply.

TheXpathexpressionscanevaluatetodifferentresulttypes.BydefaultCitrusisoperatingonNODEandSTRINGresulttypessothatyoucanvalidatesomeelementvalue.ButyoucanalsousedifferentresulttypessuchasNODESETandBOOLEAN.Seethisexamplehowthatworks:

XMLDSL

<message><validate><xpathexpression="/TestRequest/Error"value="false"result-type="boolean"/><xpathexpression="/TestRequest/Status[.='success']"value="3"result-type="number"/><xpathexpression="/TestRequest/OrderType"value="[single,multi,multi]"result-type="node-set"</validate></message>

JavaDSLdesigner

@CitrusTestpublicvoidreceiveMessageTest()receive("helloServiceServer").validate("boolean:/TestRequest/Error",false).validate("number:/TestRequest/Status[.='success']",3).validate("node-set:/TestRequest/OrderType","[single,multi,multi]").header("Operation","sayHello");

Intheexampleaboveweusedifferentexpressionresulttypes.Firstwewanttomakesurenor/TestRequest/Errorelementispresent.Thiscanbedonewithabooleanresulttypeandfalsevalue.Secondwewanttovalidatethenumberoffoundelementsfortheexpression/TestRequest/Status[.='success'].TheXPathexpressionevaluatestoanodelistthatresultsinitslistsizetobechecked.Andlastnotleastweevaluatetoanode-setresulttypewhereallvaluesinthenodelistwillbetranslatedtoacommadelimitedstringvalue.

Nowletshavealookatsomemorepowerfulvalidationexpressionsusingmatcherimplementations.UptonowwehaveseenthatXPathexpressionresultsarecomparablewithequalTooperations.Wewouldliketoaddsomemorepowerful

CitrusReferenceGuide

101Xpath

Page 102: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

validationsuchasgreaterThan,lessThan,hasSizeandmuchmore.ThereforewehaveintroducedHamcrestvalidationmatchersupportinCitrus.Hamcrestisaverypowefulmatcherlibrarythatprovidesafantasticsetofmatcherimplementations.Letsseehowwecanaddtheseinourtestcase:

XMLDSL

<message><validate><xpathexpression="/TestRequest/Error"value="@assertThat(anyOf(empty(),nullValue()))@"/><xpathexpression="/TestRequest/Status[.='success']"value="@assertThat(greaterThan(0))@"<xpathexpression="/TestRequest/OrderType"value="@assertThat(hasSize(3))@"result-type="node-set"</validate></message>

JavaDSLdesigner

@CitrusTestpublicvoidreceiveMessageTest()receive("helloServiceServer").validate("/TestRequest/Error",anyOf(empty(),nullValue())).validate("number:/TestRequest/Status[.='success']",greaterThan(0)).validate("node-set:/TestRequest/OrderType",hasSize(3)).header("Operation","sayHello");

WhenusingtheXMLDSLwehavetousetheassertThatvalidationmatchersyntaxfordefiningtheHamcrestmatchers.YoucancombinematcherimplementationasseenintheanyOf(empty(),nullValue())expression.WhenusingtheJavaDSLyoucanjustaddthematcherasexpectedresultobject.Citrusevaluatesthematchersandmakessureeverythingisasexpected.Thisisaverypowerfulvalidationmechanismasitalsoworkswithnode-setscontainingmultiplevaluesaslist.

ThisishowyoucanaddverypowerfulmessageelementvalidationinXMLusingXPathexpressions.

ExtractvariableswithXPath

Imagineyoureceiveamessageinyourtestwithsomegeneratedmessageidentifiervalues.Youhavenochancetopredicttheidentifiervaluebecauseitwasgeneratedatruntimebyaforeignapplication.Youcanignorethevalueinordertoprotectyourvalidation.Butinmanycasesyoumightneedtoreturnthisidentifierintherespective

CitrusReferenceGuide

102Xpath

Page 103: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

responsemessageorsomewhatlateroninthetest.Sowehavetosavethedynamicmessagecontentforreuseinlaterteststeps.Thesolutionissimpleandverypowerful.Wecanextractdynamicvaluesfromreceivedmessagesandsavethosetotestvariables.Addthiscodetoyourmessagereceivingaction.

XMLDSL

<extract><headername="Operation"variable="operation"/><messagepath="/TestRequest/VersionId"variable="versionId"/></extract>

JavaDSLdesigner

@CitrusTestpublicvoidreceiveMessageTest()receive("helloServiceServer").extractFromHeader("Operation","operation").extractFromPayload("//TestRequest/VersionId","versionId");

echo("Extractedoperationfromheaderis:$operation");echo("Extractedversionfrompayloadis:$versionId");

AsyoucanseeCitrusisabletoextractbothheaderandmessagepayloadcontentintotestvariables.Itdoesnotmatterifyouusenewtestvariablesorexistingvariablesastarget.Theextractionwillautomaticallycreateanewvariableincaseitdoesnotexist.Thetimethevariablewascreatedallfollowingtestactionscanaccessthetestvariablesasusual.Soyoucanreferencethevariablevaluesinresponsemessagesorotherteststepsahead.

TipWecanalsouseexpressionresulttypesinordertomanipulatethetestvariableoutcome.Incaseweuseabooleanresulttypetheexistenceofelementscanbesavedtovariablevalues.Theresulttypenode-settranslatesanodelistresulttoacommaseparatedstringofallvaluesinthisnodelist.Simplyusetheexpressionresulttypeattributesasshowninprevioussections.

XMLnamespacesinXPath

WhenitcomestoXMLnamespacesyouhavetobecarefulwithyourXPathexpressions.LetshavealookatanexamplemessagethatusesXMLnamespaces:

CitrusReferenceGuide

103Xpath

Page 104: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<ns1:TestMessagexmlns:ns1="http://citrus.com/namespace"><ns1:TestHeader><ns1:CorrelationId>_</ns1:CorrelationId><ns1:Timestamp>2001-12-17T09:30:47.0Z</ns1:Timestamp><ns1:VersionId>2</ns1:VersionId></ns1:TestHeader><ns1:TestBody><ns1:Customer><ns1:Id>1</ns1:Id></ns1:Customer></ns1:TestBody></ns1:TestMessage>

NowwewouldliketovalidatesomeelementsinthismessageusingXPath

<message><validate><xpathexpression="//TestMessage/TestHeader/VersionId"value="2"/><xpathexpression="//TestMessage/TestHeader/CorrelationId"value="$correlationId"/></validate></message>

ThevalidationwillfailalthoughtheXPathexpressionlookscorrectregardingtheXMLtree.Becausethemessageusesthenamespacexmlns:ns1="http://citrus.com/namespace"withitsprefixns1ourXPathexpressionisnotabletofindtheelements.ThecorrectXPathexpressionusesthenamespaceprefixasdefinedinthemessage.

<message><validate><xpathexpression="//ns1:TestMessage/ns1:TestHeader/ns1:VersionId"value="2"/><xpathexpression="//ns1:TestMessage/ns1:TestHeader/ns1:CorrelationId"value="$correlationId"</message>

Nowtheexpressionsworkfineandthevalidationissuccessful.Butthisisquiteerrorprone.Thisisbecausethetestisnowdependingonthenamespaceprefixthatisusedbysomeapplication.Assoonasthemessageissentwithadifferentnamespaceprefix(e.g.ns2)thevalidationwillfailagain.

Youcanavoidthiseffectwhenspecifyingyourownnamespacecontextandyourownnamespaceprefixduringvalidation.

CitrusReferenceGuide

104Xpath

Page 105: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<message><validate><xpathexpression="//pfx:TestMessage/pfx:TestHeader/pfx:VersionId"value="2"/><xpathexpression="//pfx:TestMessage/pfx:TestHeader/pfx:CorrelationId"value="$correlationId"<namespaceprefix="pfx"value="http://citrus.com/namespace"/></validate></message>

Nowthetestinindependentfromanynamespaceprefixinthereceivedmessage.Thenamespacecontextwillresolvethenamespacesandfindtheelementsalthoughthemessagemightusedifferentprefixes.Theonlythingthatmattersisthatthenamespacevalue(http://citrus.com/namespace)matches.

TipInsteadofthisnamespacecontextonvalidationlevelyoucanalsohaveaglobalnamespacecontextwhichisvalidinalltestcases.WejustaddabeaninthebasicSpringapplicationcontextconfigurationwhichdefinesglobalnamespacemappings.

<namespace-context><namespaceprefix="def"uri="http://www.consol.de/samples/sayHello"/></namespace-context>

OncedefinedthedefnamespaceprefixisvalidinalltestcasesandallXPathexpressions.Thisenablesyoutofreeyourtestcasesfromnamespaceprefixbindingsthatmightbebrokenwithtime.YoucanusetheseglobalnamespacemappingswhereverXPathexpressionsarevalidinsideatestcase(validation,ignore,extract).

DefaultnamespacesinXPath

IntheprevioussectionwehaveseenthatXMLnamespacescangettrickywithXPathvalidation.Defaultnamespacescandoevenmore!Soletslookattheexamplewithdefaultnamespaces:

<TestMessagexmlns="http://citrus.com/namespace"><TestHeader><CorrelationId>_</CorrelationId><Timestamp>2001-12-17T09:30:47.0Z</Timestamp><VersionId>2</VersionId></TestHeader><TestBody><Customer><Id>1</Id></Customer>

CitrusReferenceGuide

105Xpath

Page 106: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</TestBody></TestMessage>

Themessageusesdefaultnamespaces.ThefollowingapproachinXPathwillfailduetonamespaceproblems.

<message><validate><xpathexpression="//TestMessage/TestHeader/VersionId"value="2"/><xpathexpression="//TestMessage/TestHeader/CorrelationId"value="$correlationId"/></validate></message>

EvendefaultnamespacesneedtobespecifiedintheXPathexpressions.Lookatthefollowingcodelistingthatworksfinewithdefaultnamespaces:

<message><validate><xpathexpression="//:TestMessage/:TestHeader/:VersionId"value="2"/><xpathexpression="//:TestMessage/:TestHeader/:CorrelationId"value="$correlationId"/></validate></message>

TipItisrecommendedtousethenamespacecontextasdescribedinthepreviouschapterwhenvalidating.Onlythisapproachensuresflexibilityandstabletestcasesregardingnamespacechanges.

CitrusReferenceGuide

106Xpath

Page 107: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

UsingJSONPathJSONPathistheJSONequivalenttoXPathintheXMLmessageworld.WithJSONPathexpressionsyoucanqueryandmanipulateentriesofaJSONmessagestructure.TheJSONPathexpressionsevaluateagainstaJSONmessagewheretheJSONobjectstructureisrepresentedinadotnotatedsyntax.

YouwillseethatJSONPathisaverypowerfultechnologywhenitcomestofindobjectentriesinacomplexJSONhierarchystructure.AlsoJSONPathcanhelptodomessagemanipulationsbeforeamessageissentoutforinstance.CitrussupportsJSONPathexpressionsinvariousscenarios:

<message><elementpath="[JSONPath-Expression]"></message><validate><json-pathexpression="[JSONPath-Expression]"/></validate><extract><messagepath="[JSONPath-Expression]"></extract><ignorepath="[JSONPath-Expression]"/>

ManipulatewithJSONPath

FirstthingwewanttodowithJSONPathistomanipulateamessagecontentbeforeitisactuallysentout.Thisisveryusefulwhenworkingwithmessagefileresourcesthatarereusedaccrossmultipletestcases.EachtestcasecanmanipulatethemessagecontentindividuallywithJSONPathbeforesending.Letshavealookatthissimplesample:

<messagetype="json"><resourcefile="file:path/to/user.json"/><elementpath="$.user.name"value="Admin"/><elementpath="$.user.admin"value="true"/><elementpath="$..status"value="closed"/></message>

Weuseabasicmessagecontentfilethatiscalleduser.json.ThecontentofthefileisfollowingJSONdatastructure:

user:"id":citrus:randomNumber(10)"name":"Unknown","admin":"?","projects":

CitrusReferenceGuide

107JsonPath

Page 108: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

["name":"Project1","status":"open","name":"Project2","status":"open","name":"Project3","status":"closed"]

Citrusloadsthefilecontentanduseditasmessagepayload.BeforethemessageissentouttheJSONPathexpressionshavethechancetomanipulatethemessagecontent.AllJSONPathexpressionsareevaluatedandthegivevaluesoverwriteexistingvaluesaccordingly.Theresultingmessagelookslikefollows:

user:"id":citrus:randomNumber(10)"name":"Admin","admin":"true","projects":["name":"Project1","status":"closed","name":"Project2","status":"closed","name":"Project3","status":"closed"]

TheJSONPathexpressionshavesettheusernametoAdmin.Theadminbooleanpropertywassettotrueandallprojectstatusvaluesweresettoclosed.Nowthemessageisreadytobesentout.IncaseaJSONPathexpressionshouldfailtofindamatchingelementwithinthemessagestructurethetestcasewillfail.

CitrusReferenceGuide

108JsonPath

Page 109: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

WiththisJSONPathmechanismouareabletomanipulatemessagecontentbeforeitissentorreceivedwithinCitrus.Thismakeslifeveryeasywhenusingmessageresourcefilesthatarereusedacrossmultipletestcases.

ValidatewithJSONPath

LetscontinuetouseJSONPathexpressionswhenvalidatingareceivemessageinCitrus:

XMLDSL

<messagetype="json"><validate><json-pathexpression="$.user.name"value="Penny"/><json-pathexpression="$['user']['name']"value="$userName"/><json-pathexpression="$.user.aliases"value="["penny","jenny","nanny"]"/><json-pathexpression="$.user[?(@.admin)].password"value="@startsWith('$%00')@"/><json-pathexpression="$.user.address[?(@.type='office')]"value=""city":"Munich","street":"CompanyStreet","type":"office""/></validate></message>

JavaDSL

receive(someEndpoint).messageType(MessageType.JSON).validate("$.user.name","Penny").validate("$['user']['name']","$userName").validate("$.user.aliases","["penny","jenny","nanny"]").validate("$.user[?(@.admin)].password","@startsWith('$%00')@").validate("$.user.address[?(@.type='office')]",""city":"Munich","street":"CompanyStreet","type":"office"");

TheaboveJSONPathexpressionswillbeevaluatedwhenCitrusvalidatesthereceivedmessage.Theexpressionresultiscomparedtotheexpectedvaluewhereexpectationscanbestaticvaluesaswellastestvariablesandvalidationmatcherexpressions.IncaseaJSONPathexpressionshouldnotbeabletofindanyelementsthetestcasewillalsofail.

JSONisaprettysimpleyetpowerfulmessageformat.SimplifiedaJSONmessagejustknowsJSONObject,JSONArrayandJSONValueitems.ThehandlingofJSONObjectandJSONValueitemsinJSONPathexpressionsisstraightforward.Wejustuseadot

CitrusReferenceGuide

109JsonPath

Page 110: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

notatedsyntaxforwalkingthroughtheJSONObjecthierarchy.ThehandlingofJSONArrayitemsisalsonotverydifficulteither.CitruswilltrythebesttoconvertJSONArrayitemstoStringrepresentationvaluesforcomparison.

ImportantJSONPathexpressionswillonlyworkonJSONmessageformats.ThisiswhywehavetotellCitrusthecorrectmessageformat.BydefaultCitrusisworkingwithXMLmessagedataandthereforetheXMLvalidationmechanismsdoapplybydefault.WiththemessagetypeattributesettojsonwemakesurethatCitrusenablesJSONspecificfeaturesonthemessagevalidationsuchasJSONPathsupport.

NowletsgetabitmorecomplexwithvalidationmatchersandJSONobjectfunctions.CitrustriestogiveyouthemostcomfortablevalidationcapabilitieswhencomparingJSONobjectvaluesandJSONarrays.OnefirstthingyoucanuseisobjectfunctionslikekeySet()orsize().ThesefunctionalityisnotcoveredbyJSONPathoutofthebowbutaddedbyCitrus.Sethefollowingexampleonhowtouseit:

XMLDSL

<messagetype="json"><validate><json-pathexpression="$.user.keySet()"value="[id,name,admin,projects]"/><json-pathexpression="$.user.aliases.size()"value="3"/></validate></message>

JavaDSL

receive(someEndpoint).messageType(MessageType.JSON).validate("$.user.keySet()","[id,name,admin,projects]").validate("$.user.aliases.size()","3");

TheobjectfunctionsdoreturnspecialJSONobjectrelatedpropertiessuchasthesetofkeysforanobjectorthesizeofanJSONarray.

Nowletsgetevenmorecomfortablevalidationcapabilitieswithmatchers.CitrussupportsHamcrestmatcherswhichgivesusaverypowerfulwayofvalidatingJSONobjectelementsandarrays.Seethefollowingexamplesthatdemonstratehowthisworks:

XMLDSL

<messagetype="json">

CitrusReferenceGuide

110JsonPath

Page 111: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<validate><json-pathexpression="$.user.keySet()"value="@assertThat(contains(id,name,admin,projects))@"<json-pathexpression="$.user.aliases.size()"value="@assertThat(allOf(greaterThan(0),lessThan(5)))@"</validate></message>

JavaDSL

receive(someEndpoint).messageType(MessageType.JSON).validate("$.user.keySet()",contains("id","name","admin","projects")).validate("$.user.aliases.size()",allOf(greaterThan(0),lessThan(5)));

WhenusingtheXMLDSLwehavetousetheassertThatvalidationmatchersyntaxfordefiningtheHamcrestmatchers.YoucancombinematcherimplementationasseenintheallOf(greaterThan(0),lessThan(5))expression.WhenusingtheJavaDSLyoucanjustaddthematcherasexpectedresultobject.Citrusevaluatesthematchersandmakessureeverythingisasexpected.ThisisaverypowerfulvalidationmechanismasitcombinestheHamcrestmatchercapabilitieswithJSONmessagevalidation.

ExtractvariableswithJSONPath

Citrusisabletosavemessagecontenttotestvariablesattestruntime.Whenanincomingmessageispassingthemessagevalidationtheusercanextractsomevaluesofthatreceivedmessagetonewtestvariablesforlateruseinthetest.Thisisespeciallyhandsomewhenhavingtosendbacksomedynamicvalues.SoletssavesomevaluesusingJSONPath:

<messagetype="json"><data>user:"name":"Admin","password":"secret","admin":"true","aliases":["penny","chef","master"]</data><extract><messagepath="$.user.name"variable="userName"/><messagepath="$.user.aliases"variable="userAliases"/><messagepath="$.user[?(@.admin)].password"variable="adminPassword"/>

CitrusReferenceGuide

111JsonPath

Page 112: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</extract></message>

WiththisexamplewehaveextractedthreenewtestvariablesviaJSONPathexpressionevaluation.Thethreetestvariableswillbeavailabletoallupcomingtestactions.Thevariablevaluesare:

userName=AdminuserAliases=["penny","chef","master"]adminPassword=secret

AsyoucanseewecanalsoextractcomplexJSONObjectitemsorJSONArrayitems.ThetestvariablevalueisaStringrepresentationofthecomplexobject.

IgnorewithJSONPath

ThenextusagescenarioforJSONPathexpressionsinCitrusistheignoringofelementsduringmessagevalidation.AsyoualreadyknowCitrusprovidespowerfulvalidationmechanismsforXMLandJSONmessageformat.Theframeworkisabletocomparereceivedandexpectedmessagecontentswithpowerfulvalidatorimplementations.NowitthistimewewanttouseaJSONPathexpressionforignoringaveryspecificentryintheJSONobjectstructure.

<messagetype="json"><data>"users":["name":"Jane","token":"?","lastLogin":0,"name":"Penny","token":"?","lastLogin":0,"name":"Mary","token":"?","lastLogin":0]</data><ignoreexpression="$.users[*].token"/>

CitrusReferenceGuide

112JsonPath

Page 113: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<ignoreexpression="$..lastLogin"/></message>

ThistimeweaddJSONPathexpressionsasignorestatements.Thismeansthatweexplicitlyleaveouttheevaluatedelementsfromvalidation.Obviouslythismechanismisagoodthingtodowhendynamicmessagedatasimplyisnotdeterministicsuchastimestampsanddynamicidentifiers.IntheexampleaboveweexplicitlyskipthetokenentryandalllastLoginvaluesthatareobviouslytimestampvaluesinmilliseconds.

TheJSONPathevaluationisverypowerfulwhenitcomestoselectasetofJSONobjectsandelements.ThisishowwecanignoreseveralelementswithonesingleJSONPathexpressionwhichisverypowerful.

CitrusReferenceGuide

113JsonPath

Page 114: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TestactionsThischaptergivesabriefdescriptiontoalltestactionsthatatestercanincorporateintothetestcase.Besidessendingandreceivingmessagesthetestermayaccesstheseactionsinordertobuildamorecomplextestscenariothatfitsthedesiredusecase.

CitrusReferenceGuide

114Actions

Page 115: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Sendingmessages

Inaintegrationtestscenariowewanttotriggerprocessesandcallinterfaceservicesonthesystemundertest.Inordertodothisweneedtobeabletosendmessagestovariousmessagetransports.ThereforethesendmessagetestactioninCitrusisoneofthemostimportanttestactions.FirstofallletushavealookattheCitrusmessagedefinitioninCitrus:

Amessageconsistsofamessageheader(name-valuepairs)andamessagepayload.Laterinthissectionwewillseedifferentwaysofconstructingamessagewithpayloadandheadervalues.Butfirstofalllet'sconcentrateonasimplesendingmessageactioninsideatestcase.

XMLDSL

<testcasename="SendMessageTest"><description>Basicsendmessageexample</description>

<variables><variablename="text"value="HelloCitrus!"/><variablename="messageId"value="Mx1x123456789"/></variables>

<actions><sendendpoint="helloServiceEndpoint"><messagename="helloMessage">

CitrusReferenceGuide

115Send

Page 116: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<payload><TestMessage><Text>$text</Text></TestMessage></payload></message><header><elementname="Operation"value="sayHello"/><elementname="MessageId"value="$messageId"/></header></send></actions></testcase>

Themessagenameisoptionalanddefinesthemessageidentifierinthelocalmessagestore.Thismessagenameisveryusefulwhenaccessingthemessagecontentlateronduringthetestcase.Thelocalmessagestoreishandledpertestcaseandcontainsallexchangedmessages.Thesampleusesbothheaderandpayloadasmessagepartstosend.Inbothpartsyoucanusevariabledefinitions(see$textand$messageId).Sofirstofallletusrecapwhatvariablesdo.Testvariablesaredefinedattheverybeginningofthetestcaseandarevalidthroughoutallactionsthattakeplaceinthetest.Thismeansthatactionscansimplyreferenceavariablebytheexpression$variable-name.

TipUsevariableswhereveryoucan!Atleasttheimportantentitiesofatestshouldbedefinedasvariablesatthebeginning.Thetestcaseimprovesmaintainabilityandflexibilitywhenusingvariables.

Nowletshaveacloserlookatthesendingaction.The'endpoint'attributemightcatchyourattentionfirst.ThisattributereferencesamessageendpointinCitrusconfigurationbyname.Aspreviouslymentionedthemessageendpointdefinitionlivesinaseparateconfigurationfileandcontainstheactualmessagetransportsettings.Inthisexamplethe"helloServiceEndpoint"isreferencedwhichisamessageendpointforsendingoutmessagesviaJMSorHTTPforinstance.

Thetestcaseisnotawareofanytransportdetails,becauseitdoesnothaveto.Theadvantagesareobvious:Ontheonehandmultipletestcasescanreferencethemessageendpointdefinitionforbetterreuse.Secondlytestcasesareindependentofmessagetransportdetails.Soconnectionfactories,usercredentials,endpointurivaluesandsoonarenotpresentinthetestcase.

CitrusReferenceGuide

116Send

Page 117: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Inotherwordsthe"endpoint"attributeofthe<send>elementspecifieswhichmessageendpointdefinitiontouseandthereforewherethemessageshouldgoto.OnceagainallavailablemessageendpointsareconfiguredinaseparateCitrusconfigurationfile.Wewillcometothislateron.Besuretoalwayspicktherightmessageendpointtypeinordertopublishyourmessagetotherightdestination.

IfyoudonotliketheXMLlanguageyoucanalsousepureJavacodetodefinethesametest.InJavayouwouldalsomakeuseofthemessageendpointdefinitionandreferencethisinstance.ThesametestasshownaboveinJavaDSLlookslikethis:

JavaDSLdesigner

importorg.testng.ITestContext;importorg.testng.annotations.Test;importcom.consol.citrus.annotations.CitrusTest;importcom.consol.citrus.dsl.testng.TestNGCitrusTestDesigner;

@TestpublicclassSendMessageTestDesignerextendsTestNGCitrusTestDesigner

@CitrusTest(name="SendMessageTest")publicvoidsendMessageTest()description("Basicsendmessageexample");

variable("text","HelloCitrus!");variable("messageId","Mx1x123456789");

send("helloServiceEndpoint").name("helloMessage").payload("<TestMessage>"+"<Text>$text</Text>"+"</TestMessage>").header("Operation","sayHello").header("RequestTag","$messageId");

JavaDSLrunner

importorg.testng.ITestContext;importorg.testng.annotations.Test;importcom.consol.citrus.annotations.CitrusTest;importcom.consol.citrus.dsl.testng.TestNGCitrusTestRunner;

@TestpublicclassSendMessageTestRunnerextendsTestNGCitrusTestRunner

CitrusReferenceGuide

117Send

Page 118: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

@CitrusTest(name="SendMessageTest")publicvoidsendMessageTest()variable("text","HelloCitrus!");variable("messageId","Mx1x123456789");

send(action->action.endpoint("helloServiceEndpoint").name("helloMessage").payload("<TestMessage>"+"<Text>$text</Text>"+"</TestMessage>").header("Operation","sayHello").header("RequestTag","$messageId"));

InsteadofusingtheXMLtagsforsendweusemethodsfromTestNGCitrusTestDesignerclass.Thesamemessageendpointisreferencedwithinthesendmessageaction.

Nowthatthemessagesenderpatternisclearwecanconcentrateonhowtospecifythemessagecontenttobesent.ThereareseveralpossibilitiesforyoutodefinemessagecontentinCitrus:

message:Thiselementconstructsthemessagetobesent.Thereareseveralchildelementsavailable:payload:NestedXMLpayloadasdirectchildnode.data:InlineCDATAdefinitionofthemessagepayloadresource:ExternalfileresourceholdingthemessagepayloadThesyntaxwouldbe:<resourcefile="classpath:com/consol/citrus/messages/TestRequest.xml"/>Thefilepathprefixindicatestheresourcetype,sothefilelocationisresolvedeitherasfilesystemresource(file:)orclasspathresource(classpath:).element:ExplicitlyoverwritevaluesintheXMLmessagepayloadusingXPath.Youcanreplacemessagecontentwithdynamicvaluesbeforesending.Eachentryprovidesa"path"and"value"attribute.The"path"givesaXPathexpressionevaluatingtoaXMLnodeelementorattributeinthemessage.The"value"canbeavariableexpressionoranyotherstaticvalue.Citruswillreplacethevaluebeforesendingthemessage.header:Definesaheaderforthemessage(e.g.JMSheaderinformationorSOAPheader):element:Eachheaderreceivesa"name"and"value".The"name"willbethenameoftheheaderentryand"value"itsrespectivevalue.Againtheusageofvariableexpressionsasvalueissupportedhere,too.

CitrusReferenceGuide

118Send

Page 119: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

XMLDSL

<sendendpoint="helloServiceEndpoint"><message><payload><!--messagepayloadasXML--></payload></message></send>

<sendendpoint="helloServiceEndpoint"><message><data><![CDATA[<!--messagepayloadasXML-->]]></data></message></send>

<sendendpoint="helloServiceEndpoint"><message><resourcefile="classpath:com/consol/citrus/messages/TestRequest.xml"/></message></send>

Themostimportantthingwhendealingwithsendingactionsistopreparethemessagepayloadandheader.YouareabletoconstructthemessagepayloadeitherbynestedXMLchildnodes(payload),asinlineCDATA()orexternalfile().

NoteSometimesthenestedXMLmessagepayloadelementsmaycauseXSDschemavalidationruleviolations.ThisisbecauseofvariablevaluesnotfittingtheXSDschemarulesforexample.InthisscenarioyoucouldalsousesimpleCDATAsectionsaspayloaddata.Inthiscaseyouneedtousethe<data>elementincontrasttothe<payload>elementthatwehaveusedinourexamplessofar.

WiththisalternativeyoucanskiptheXMLschemavalidationfromyourIDEatdesigntime.UnfortunatelyyouwillloosetheXSDautocompletionfeaturesmanyXMLeditorsofferwhenconstructingyourpayload.

TheThesamepossibilitiesapplytotheCitrusJavaDSL.

JavaDSLdesigner

CitrusReferenceGuide

119Send

Page 120: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

@CitrusTestpublicvoidmessagingTest()send("helloServiceEndpoint").payload("<TestMessage>"+"<Text>Hello!</Text>"+"</TestMessage>");

@CitrusTestpublicvoidmessagingTest()send("helloServiceEndpoint").payload(newClassPathResource("com/consol/citrus/messages/TestRequest.xml"));

@CitrusTestpublicvoidmessagingTest()send("helloServiceEndpoint").payloadModel(newTestRequest("HelloCitrus!"));

@CitrusTestpublicvoidmessagingTest()send("helloServiceEndpoint").message(newDefaultMessage("HelloWorld!")));

BesidesdefiningmessagepayloadsasnormalStringsandviaexternalfileresource(classpathandfilesystem)youcanalsousemodelobjectsaspayloaddatainJavaDSL.ThismodelobjectpayloadrequiresapropermessagemarshallerthatshouldbeavailableasSpringbeaninsidetheapplicationcontext.BydefaultCitrusissearchingforabeanoftypeorg.springframework.oxm.Marshaller.

IncaseyouhavemultiplemessagemarshallersintheapplicationcontextyouhavetotellCitruswhichonetouseinthisparticularsendmessageaction.

@CitrusTestpublicvoidmessagingTest()send("helloServiceEndpoint").payloadModel(newTestRequest("HelloCitrus!"),"myMessageMarshallerBean");

CitrusReferenceGuide

120Send

Page 121: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

NowCitruswillmarshalthemessagepayloadwiththemessagemarshallerbeannamedmyMessageMarshallerBean.Thiswayyoucanhavemultiplemessagemarshallerimplementationsactiveinyourproject(XML,JSON,andsoon).

LastnotleastthemessagecanbedefinedasCitrusmessageobject.HereyoucanchooseoneofthedifferentmessageimplementationsusedinCitrusforSOAP,HttporJMSmessages.Oryoujustusethedefaultmessageimplementationormaybeacustomimplementation.

Beforesendingtakesplaceyoucanexplicitlyoverwritesomemessagevaluesinpayload.Youcanthinkofoverwritingspecificmessageelementswithvariablevalues.AlsoyoucanoverwritevaluesusingXPath(xpath)orJSONPath(json-path)expressions.

Themessageheaderispartofourdutyofdefiningpropermessages,too.SoCitrususesname-valuepairslike"Operation"and"MessageId"inthenextexampletosetmessageheaderentries.Dependingonwhatmessageendpointisusedandwhichmessagetransportunderneaththeheadervalueswillbeshippedindifferentways.InJMStheheadersgototheheadersectionofthemessage,inHttpwesetmimeheadersaccordingly,inSOAPwecanaccesstheSOAPheaderelementsandsoon.Citrusaimstodothehardworkforyou.SoCitrusknowshowtosetheadersondifferentmessagetransports.

XMLDSL

<sendendpoint="helloServiceEndpoint"><message><payload><TestMessage><Text>Hello!</Text></TestMessage></payload></message><header><elementname="Operation"value="sayHello"/></header></receive>

Themessageheaderstosendaredefinedbyasimplenameandvaluepair.Ofcourseyoucanusetestvariablesinheadervaluesaswell.Let'sseehowthislookslikeinJavaDSL:

JavaDSLdesigner

CitrusReferenceGuide

121Send

Page 122: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

@CitrusTestpublicvoidmessagingTest()receive("helloServiceEndpoint").payload("<TestMessage>"+"<Text>Hello!</Text>"+"</TestMessage>").header("Operation","sayHello");

JavaDSLrunner

@CitrusTestpublicvoidmessagingTest()receive(action->action.endpoint("helloServiceEndpoint").payload("<TestMessage>"+"<Text>Hello!</Text>"+"</TestMessage>").header("Operation","sayHello"));

ThisisbasicallyhowtosendmessagesinCitrus.Thetestcaseisresponsibleforconstructingthemessagecontentwhilethepredefinedmessageendpointholdstransportspecificsettings.Testcasesreferenceendpointcomponentstopublishmessagestotheoutsideworld.Thevariablesupportinmessagepayloadandmessageheaderenablesyoutoadddynamicvaluesbeforesendingoutthemessage.

CitrusReferenceGuide

122Send

Page 123: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Receivingmessages

Justlikesendingmessagesthereceivingpartisaveryimportantactioninanintegrationtest.HonestlythereceiveactionisevenmoreimportantinCitrusaswealsowanttovalidatetheincomingmessagecontents.Wearewritingatestsowealsoneedassertionsandchecksthateverythingworksasexpected.

Asalreadymentionedbeforeamessageconsistsofamessageheader(name-valuepairs)andamessagepayload.Laterinthisdocumentwewillseehowtovalidateincomingmessageswithpayloadandheadervalues.Westartwithaverysimpleexample:

XMLDSL

<receiveendpoint="helloServiceEndpoint"><messagename="helloRequest"><payload><TestMessage><Text>$text</Text></TestMessage></payload></message><header><elementname="Operation"value="sayHello"/><elementname="MessageId"value="$messageId"/></header></receive>

Overallthereceivemessageactionlooksquitesimilartothesendmessageaction.Conceptsareidenticalaswedefinethemessagecontentwithpayloadandheadervalues.Themessagenameisoptionalanddefinesthemessageidentifierinthelocalmessagestore.Thismessagenameisveryusefulwhenaccessingthemessagecontentlateronduringthetestcase.Thelocalmessagestoreishandledpertestcaseandcontainsallexchangedmessages.

Wecanusetestvariablesinbothmessagepayloadanheaders.NowletushavealookattheJavaDSLrepresentationofthissimpleexample:

JavaDSLdesigner

@CitrusTestpublicvoidmessagingTest()receive("helloServiceEndpoint")

CitrusReferenceGuide

123Receive

Page 124: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

.name("helloRequest").payload("<TestMessage>"+"<Text>$text</Text>"+"</TestMessage>").header("Operation","sayHello").header("MessageId","$messageId");

JavaDSLrunner

@CitrusTestpublicvoidmessagingTest()receive(action->action.endpoint("helloServiceEndpoint").name("helloRequest").payload("<TestMessage>"+"<Text>$text</Text>"+"</TestMessage>").header("Operation","sayHello").header("MessageId","$messageId"));

Thereceiveactionwaitsforamessagetoarrive.Thewholetestexecutionisstoppedwhilewaitingforthemessage.Thisisimportanttoensurethestepbysteptestworkflowprocessing.Ofcourseyoucanspecifymessagetimeoutssothereceiverwillonlywaitagivenamountoftimebeforeraisingatimeouterror.Followingfromthattimeoutexceptionthetestcasefailsasthemessagedidnotarriveintime.Citrusdefinesdefaulttimeoutsettingsforallmessagereceivingtasks.

Inagoodcasescenariothemessagearrivesintimeandthecontentcanbevalidatedasanextstep.Thisvalidationcanbedoneinvariousways.OntheonehandyoucanspecifyawholeXMLmessagethatyouexpectascontroltemplate.Inthiscasethereceivedmessagestructureiscomparedtotheexpectedmessagecontentelementbyelement.Ontheotherhandyoucanuseexplicitelementvalidationwhereonlyasmallsubsetofmessageelementsisincludedintovalidation.

BesidesthemessagepayloadCitruswillalsoperformvalidationonthereceivedmessageheadervalues.Testvariableusageissupportedasusualduringthewholevalidationprocessforpayloadandheaderchecks.

Ingeneralthevalidationcomponent(validator)inCitrusworkshandinhandwithamessagereceivingcomponentasthefollowingfigureshows:

CitrusReferenceGuide

124Receive

Page 125: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Themessagereceivingcomponentpassesthemessagetothevalidatorwheretheindividualvalidationstepsareperformed.Letushaveacloserlookatthevalidationoptionsandfeaturesstepbystep.

Validatemessagepayloads

Themostdetailedvalidationofincomingmessagesistodefinesomeexpectedmessagepayload.TheCitrusmessagevalidatorwillthenperformadetailedmessagepayloadcomparison.Theincomingmessagehastomatchexactlytotheexpectedmessagepayload.ThedifferentmessagevalidatorimplementationsinCitrusprovidedeepcomparisonofmessagestructuressuchasXML,JSONandsoon.

Sobydefininganexpectedmessagepayloadwevalidatetheincomingmessageinsyntaxandsemantics.Incaseadifferenceisidentifiedbythemessagevalidatorthevalidationandthetestcasefailswithrespectiveexceptions.Thisishowyoucandefinemessagepayloadsinreceiveaction:

XMLDSL

<receiveendpoint="helloServiceEndpoint"><message><payload><!--messagepayloadasXML--></payload></message></receive>

<receiveendpoint="helloServiceEndpoint"><message><data><![CDATA[<!--messagepayloadasXML-->]]></data></message></receive>

<receiveendpoint="helloServiceEndpoint"><message>

CitrusReferenceGuide

125Receive

Page 126: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<resourcefile="classpath:com/consol/citrus/messages/TestRequest.xml"/></message></receive>

Thethreeexamplesaboverepresentthreedifferentwaysofdefiningthemessagepayloadinareceivemessageaction.OntheonehandwecanuseinlinemessagepayloadsasnestedXMLorCDATAsectionsinthetest.Ontheotherhandwecanloadthemessagecontentfromexternalfileresource.

NoteSometimesthenestedXMLmessagepayloadelementsmaycauseXSDschemavalidationruleviolations.ThisisbecauseofvariablevaluesnotfittingtheXSDschemarulesforexample.InthisscenarioyoucouldalsousesimpleCDATAsectionsaspayloaddata.Inthiscaseyouneedtousethe<data>elementincontrasttothe<payload>elementthatwehaveusedinourexamplessofar.

WiththisalternativeyoucanskiptheXMLschemavalidationfromyourIDEatdesigntime.UnfortunatelyyouwillloosetheXSDautocompletionfeaturesmanyXMLeditorsofferwhenconstructingyourpayload.

InJavaDSLwealsohavemultipleoptionsforspecifyingthemessagepayloads:

JavaDSLdesigner

@CitrusTestpublicvoidmessagingTest()receive("helloServiceEndpoint").payload("<TestMessage>"+"<Text>Hello!</Text>"+"</TestMessage>");

@CitrusTestpublicvoidmessagingTest()receive("helloServiceEndpoint").payload(newClassPathResource("com/consol/citrus/messages/TestRequest.xml"));

@CitrusTestpublicvoidmessagingTest()receive("helloServiceEndpoint").payloadModel(newTestRequest("HelloCitrus!"));

CitrusReferenceGuide

126Receive

Page 127: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

@CitrusTestpublicvoidmessagingTest()receive("helloServiceEndpoint").message(newDefaultMessage("HelloWorld!")));

TheexamplesaboverepresentthebasicvariationsofhowtodefinemessagepayloadsinCitrusJavaDSL.ThepayloadcanbeasimpleStringoraSpringfileresource(classpathorfilesystem).Inadditiontothatwecanuseamodelobject.WhenusingmodelobjectsaspayloadsweneedapropermessagemarshallerimplementationintheSpringapplicationcontext.Bydefaultthisisamarshallerbeanoftypeorg.springframework.oxm.MarshallerthathastobepresentintheSpringapplicationcontext.YoucanaddsuchabeanforXMLandJSONmessagemarshallingforinstance.

IncaseyouhavemultiplemessagemarshallersintheapplicationcontextyouhavetotellCitruswhichonetouseinthisparticularsendmessageaction.

@CitrusTestpublicvoidmessagingTest()receive("helloServiceEndpoint").payloadModel(newTestRequest("HelloCitrus!"),"myMessageMarshallerBean");

NowCitruswillmarshalthemessagepayloadwiththemessagemarshallerbeannamedmyMessageMarshallerBean.Thiswayyoucanhavemultiplemessagemarshallerimplementationsactiveinyourproject(XML,JSON,andsoon).

LastnotleastthemessagecanbedefinedasCitrusmessageobject.HereyoucanchooseoneofthedifferentmessageimplementationsusedinCitrusforSOAP,HttporJMSmessages.Oryoujustusethedefaultmessageimplementationormaybeacustomimplementation.

IngeneraltheexpectedmessagecontentcanbemanipulatedusingXPath(xpath)orJSONPath(json-path).Inadditiontothatyoucanignoresomeelementsthatareskippedincomparison.Wewilldescribethislateroninthissection.Nowletscontinuewithmessageheadervalidation.

Validatemessageheaders

CitrusReferenceGuide

127Receive

Page 128: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Messageheadersareusedwidelyinenterprisemessagingsolution:Themessageheadersarepartofthemessagesemanticsandneedtobevalidated,too.Citruscanvalidatemessageheaderbynameandvalue.

XMLDSL

<receiveendpoint="helloServiceEndpoint"><message><payload><TestMessage><Text>Hello!</Text></TestMessage></payload></message><header><elementname="Operation"value="sayHello"/></header></receive>

Theexpectedmessageheadersaredefinedbyanameandvaluepair.Citruswillcheckthattheexpectedmessageheaderispresentandwillcheckthevalue.IncasethemessageheaderisnotfoundorthevaluedoesnotmatchCitruswillraiseanexceptionandthetestfails.Youcanusevalidationmatchers(validation-matchers)foramorepowerfulvalidationofheadervalues,too.

Let'sseehowthislookslikeinJavaDSL:

JavaDSLdesigner

@CitrusTestpublicvoidmessagingTest()receive("helloServiceEndpoint").payload("<TestMessage>"+"<Text>Hello!</Text>"+"</TestMessage>").header("Operation","sayHello");

JavaDSLrunner

@CitrusTestpublicvoidmessagingTest()receive(action->action.endpoint("helloServiceEndpoint").payload("<TestMessage>"+"<Text>Hello!</Text>"+"</TestMessage>")

CitrusReferenceGuide

128Receive

Page 129: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

.header("Operation","sayHello"));

HeaderdefinitioninJavaDSLisstraightforwardaswejustdefinenameandvalueasusual.ThiscompletesthemessagevalidationwhenreceivingamessageinCitrus.ThemessagevalidatorimplementationsmayaddadditionalvalidationcapabilitiessuchasXMLschemavalidationorXPathandJSONPathvalidation.Pleaserefertotherespectivechaptersinthisguidetolearnmoreaboutthat.

Messageselectors

The<selector>elementinsidethereceivingactiondefineskey-valuepairsinordertofilterthemessagesbeingreceived.Thefilterappliestothemessageheaders.Thismeansthatareceiverwillonlyacceptmessagesmatchingaheaderelementvalue.Inmessagingapplicationstheheaderinformationoftenholdsmessageids,correlationids,operationnamesandsoon.Withthisinformationgivenyoucanexplicitlylistenformessagesthatbelongtoyourtestcase.Thisisveryhelpfultoavoidreceivingmessagesthatarestillavailableonthemessagedestination.

Letssaythetestedsoftwareapplicationkeepssendingmessagesthatbelongtoprevioustestcases.Thiscouldhappeninretrysituationswheretheapplicationerrorhandlingautomaticallytriestosolveacommunicationproblemthatoccurredduringprevioustestcases.Asaresultamessagedestination(e.g.aJMSmessagequeue)containsmessagesthatarenotvalidanymoreforthecurrentlyrunningtestcase.Thetestcasemightfailbecausethereceivedmessagedoesnotapplytotheactualusecase.Sowewilldefinitelyrunintovalidationerrorsastheexpectedmessagecontrolvaluesdonotmatch.

Nowwehavetofindawaytoavoidtheseproblems.Thetestcouldfilterthemessagesonadestinationtoonlyreceivemessagesthatapplyfortheusecasethatisbeingtested.TheJavaMessagingSystem(JMS)cameupwithamessageheaderselectorthatwillonlyacceptmessagesthatfittheexpectedheadervalues.

Letushaveacloserlookatamessageselectorinsideareceivingaction:

XMLDSL

<selector><element>name="correlationId"value="Cx1x123456789"</element><element>name="operation"value="getOrders"</element></selector>

CitrusReferenceGuide

129Receive

Page 130: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

JavaDSLdesigner

@CitrusTestpublicvoidreceiveMessageTest()receive("testServiceEndpoint").selector("correlationId='Cx1x123456789'ANDoperation='getOrders'");

JavaDSLrunner

@CitrusTestpublicvoidreceiveMessageTest()receive(action->action.endpoint("testServiceEndpoint").selector("correlationId='Cx1x123456789'ANDoperation='getOrders'"));

Thisexampleshowshowmessageselectorswork.Theselectorwillonlyacceptmessagesthatmeetthecorrelationidandtheoperationintheheadervalues.Allothermessagesonthemessagedestinationareignored.TheselectorelementsareautomaticallyassociatedtoeachotherusingthelogicalANDoperator.Thismeansthatthemessageselectorstringwouldlooklikethis:correlationId='Cx1x123456789'ANDoperation='getOrders'.

Insteadofusingseveralelementsintheselectoryoucanalsodefineaselectorstringdirectlywhichgivesyoumorepowerinconstructingtheselectionlogicyourself.ThiswayyoucanuseANDlogicaloperatorsyourself.

<selector><value>correlationId='Cx1x123456789'ANDoperation='getOrders'</value></selector>

ImportantIncaseyouwanttoruntestsinparallelmessageselectorsbecomeessentialinyourtestcases.Thedifferenttestsrunningatthesametimewillstealmessagesfromeachotherwhenyoulackofmessageselectionmechanisms.

ImportantPreviouslyonlyJMSmessagedestinationsofferedsupportformessageselectors!WithCitrusversion1.2weintroducedmessageselectorsupportforSpringIntegrationmessagechannels,too(seemessage-channel-selector-support).

GroovyMarkupBuilder

CitrusReferenceGuide

130Receive

Page 131: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

WiththeGroovyMarkupBuilderyoucanbuildXMLmessagepayloadsinasimpleway,withouthavingtowritethetypicalXMLoverhead.ForexampleweuseaGroovyscripttoconstructtheXMLmessagetobesentout.InsteadofaplainCDATAXMLsectionorthenestedpayloadXMLdatawewriteaGroovyscriptsnippet.TheGroovyMarkupBuildergeneratestheXMLmessagepayloadwithexactlythesameresult:

XMLDSL

<sendendpoint="helloServiceEndpoint"><message><buildertype="groovy">markupBuilder.TestMessageMessageId('$messageId')Timestamp('?')VersionId('2')Text('HelloCitrus!')</builder><elementpath="/TestMessage/Timestamp"value="$createDate"/></message><header><elementname="Operation"value="sayHello"/><elementname="MessageId"value="$messageId"/></header></send>

WeusethebuilderelementwithtypegroovyandtheMarkupBuildercodeisdirectlywrittentothiselement.Asyoucanseefromtheexampleabove,youcanmixXPathandGroovymarkupbuildercode.TheMarkupBuildersyntaxisveryeasyandfollowsthesimplerule:markupBuilder.ROOT-ELEMENTCHILD-ELEMENTS.HoweverthetesterhastofollowsomesimplerulesandnamingconventionswhenusingtheCitrusMarkupBuilderextension:

TheMarkupBuilderisaccessedwithinthescriptoveranobjectnamedmarkupBuilder.Thenameofthecustomrootelementfollowswithallitschildelements.Childelementsmaybedefinedwithincurlybracketsaftertheroot-element(thesameappliesforfurthernestedchildelements)Attributesandelementvaluesaredefinedwithinroundbrackets,aftertheelementnameAttributeandelementvalueshavetostandwithinapostrophes(e.g.attribute-name:'attribute-value')

CitrusReferenceGuide

131Receive

Page 132: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TheGroovyMarkupBuilderscriptmayalsobeusedwithinreceiveactionsasshowninthefollowinglisting:

XMLDSL

<sendendpoint="helloServiceEndpoint"><message><buildertype="groovy"file="classpath:com/consol/citrus/groovy/helloRequest.groovy"/></message></send>

<receiveendpoint="helloServiceEndpoint"timeout="5000"><message><buildertype="groovy">markupBuilder.TestResponse(xmlns:'http://www.consol.de/schemas/samples/sayHello.xsd')MessageId('$messageId')CorrelationId('$correlationId')User('HelloService')Text('Hello$user')</builder></message></receive>

Asyoucanseeitisalsopossibletodefinethescriptasexternalfileresource.Inadditiontothatnamespacesupportisgivenasnormalattributedefinitionwithintheroundbracketsaftertheelementname.

TheMarkupBuilderimplementationinGroovyoffersgreatpossibilitiesindefiningmessagepayloads.WedonotneedtowriteXMLtagoverheadandwecanconstructcomplexmessagepayloadswithGroovylogiclikeiterationsandconditionalelements.FordetailedMarkupBuilderdescriptionspleaseseetheofficialGroovydocumentation.

CitrusReferenceGuide

132Receive

Page 133: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Databaseactions

Inmanycasesitisnecessarytoaccessthedatabaseduringatest.Thisenablesatestertoalsovalidatethepersistentdatainadatabase.Itmightalsobehelpfultopreparethedatabasewithsometestdatabeforerunningatest.Youcandothisusingthetwodatabaseactionsthataredescribedinthefollowingsections.

IngeneralCitrushandlesSELECTstatementsdifferentlytootherstatementslikeINSERT,UPDATEandDELETE.WhenexecutingaSQLquerywithSELECTyouareabletoaddvalidationstepsontheresultsetsreturnedfromthedatabase.ThisisnotallowedwhenexecutingupdatestatementslikeINSERT,UPDATE,DELETE.

ImportantDonotmixstatementsoftypeSELECTwithothersinasinglesqltestaction.ThiswillleadtoerrorsbecausevalidationstepsarenotvalidforstatementsotherthanSELECT.Pleaseuseseparatetestactionsforupdatestatements.

SQLupdate,insert,delete

TheactionsimplyexecutesagroupofSQLstatementsinordertochangedatainadatabase.Typicallytheactionisusedtopreparethedatabaseatthebeginningofatestortocleanupthedatabaseattheendofatest.YoucanspecifySQLstatementslikeINSERT,UPDATE,DELETE,CREATETABLE,ALTERTABLEandmanymore.

OntheonehandyoucanspecifythestatementsasinlineSQLorstoredinanexternalSQLresourcefileasshowninthenexttwoexamples.

XMLDSL

<actions><sqldatasource="someDataSource"><statement>DELETEFROMCUSTOMERS</statement><statement>DELETEFROMORDERS</statement></sql>

<sqldatasource="myDataSource"><resourcefile="file:tests/unit/resources/script.sql"/></sql></actions>

JavaDSLdesigner

@Autowired

CitrusReferenceGuide

133Database

Page 134: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

@Qualifier("myDataSource")privateDataSourcedataSource;

@CitrusTestpublicvoidsqlTest()sql(dataSource).statement("DELETEFROMCUSTOMERS").statement("DELETEFROMORDERS");

sql(dataSource).sqlResource("file:tests/unit/resources/script.sql");

JavaDSLrunner

@Autowired@Qualifier("myDataSource")privateDataSourcedataSource;

@CitrusTestpublicvoidsqlTest()sql(action->action.dataSource(dataSource).statement("DELETEFROMCUSTOMERS").statement("DELETEFROMORDERS"));

sql(action->action.dataSource(dataSource).sqlResource("file:tests/unit/resources/script.sql"));

ThefirstactionusesinlineSQLstatementsdefineddirectlyinsidethetestcase.ThenextactionusesanexternalSQLresourcefileinstead.ThefileresourcecanholdseveralSQLstatementsseparatedbynewlines.Allstatementsinsidethefileareexecutedsequentiallybytheframework.

ImportantYouhavetopayattentiontosomeruleswhendealingwithexternalSQLresources.

EachstatementshouldbegininanewlineItisnotallowedtodefinestatementswithwordwrappingCommentsbeginwithtwodashes"--"

NoteTheexternalfileisreferencedeitherasfilesystemresourceorclasspathresource,byusingthe"file:"or"classpath:"prefix.

CitrusReferenceGuide

134Database

Page 135: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Bothexamplesusethe"datasource"attribute.Thisvaluedefinesthedatabasedatasourcetobeused.Theconnectiontoadatasourceismandatory,becausethetestcasedoesnotknowaboutusercredentialsordatabasenames.The'datasource'attributereferencespredefineddatasourcesthatarelocatedinaseparateSpringconfigurationfile.

SQLquery

ThequeryactionisspeciallydesignedtoexecuteSQLqueries(SELECT*FROM).Sothetestisabletoreaddatafromadatabase.Thequeryresultsarevalidatedagainstexpecteddataasshowninthenextexample.

XMLDSL

<sqldatasource="testDataSource"><statement>selectNAMEfromCUSTOMERSwhereID='$customerId'</statement><statement>selectcount(*)fromERRORS</statement><statement>selectIDfromORDERSwhereDESCLIKE'Def%'</statement><statement>selectDESCRIPTIONfromORDERSwhereID='$id'</statement>

<validatecolumn="ID"value="1"/><validatecolumn="NAME"value="Christoph"/><validatecolumn="COUNT(*)"value="$rowsCount"/><validatecolumn="DESCRIPTION"value="null"/></sql>

JavaDSLdesigner

@Autowired@Qualifier("testDataSource")privateDataSourcedataSource;

@CitrusTestpublicvoiddatabaseQueryTest()query(dataSource).statement("selectNAMEfromCUSTOMERSwhereCUSTOMER_ID='$customerId'").statement("selectCOUNT(1)asoverall_cntfromERRORS").statement("selectORDER_IDfromORDERSwhereDESCRIPTIONLIKE'Migrate%'").statement("selectDESCRIPTIONfromORDERSwhereORDER_ID=2").validate("ORDER_ID","1").validate("NAME","Christoph").validate("OVERALL_CNT","$rowsCount").validate("DESCRIPTION","NULL");

CitrusReferenceGuide

135Database

Page 136: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

JavaDSLrunner

@Autowired@Qualifier("testDataSource")privateDataSourcedataSource;

@CitrusTestpublicvoiddatabaseQueryTest()query(action->action.dataSource(dataSource).statement("selectNAMEfromCUSTOMERSwhereCUSTOMER_ID='$customerId'").statement("selectCOUNT(1)asoverall_cntfromERRORS").statement("selectORDER_IDfromORDERSwhereDESCRIPTIONLIKE'Migrate%'").statement("selectDESCRIPTIONfromORDERSwhereORDER_ID=2").validate("ORDER_ID","1").validate("NAME","Christoph").validate("OVERALL_CNT","$rowsCount").validate("DESCRIPTION","NULL"));

Theactionoffersawiderangeofvalidatingfunctionalityfordatabaseresultsets.FirstofallyouhavetoselectthedataviaSQLstatements.HereagainyouhavethechoicetouseinlineSQLstatementsorexternalfileresourcepattern.

Theresultsetsarevalidatedthroughelements.Itispossibletodoadetailedcheckoneveryselectedcolumnoftheresultset.Simplyrefertotheselectedcolumnnameinordertovalidateitsvalue.Theusageoftestvariablesissupportedaswellasdatabaseexpressionslikecount(),avg(),min(),max().

Yousimplydefinetheentrywiththecolumnnameasthe"column"attributeandanyexpectedvalueexpressionasexpected"value".Theframeworkthenwillcheckthecolumntofittheexpectedvalueandraisevalidationerrorsincaseofmismatch.

LookingatthefirstSELECTstatementintheexampleyouwillseethattestvariablesaresupportedintheSQLstatements.Theframeworkwillreplacethevariablewithitsrespectivevaluebeforesendingittothedatabase.

Inthevalidationsectionvariablescanbeusedtoo.Lookatthethirdvalidationentry,wherethevariable"$rowsCount"isused.Thelastvalidationinthisexampleshows,thatNULLvaluesarealsosupportedasexpectedvalues.

Ifasinglevalidationhappenstofail,thewholeactionwillfailwithrespectivevalidationerrors.

CitrusReferenceGuide

136Database

Page 137: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ImportantThevalidationwith""meetssinglerowresultsetsasyouspecifyasinglecolumncontrolvalue.Incaseyouhavemultiplerowsinaresultsetyouratherneedtovalidatethecolumnswithmultiplecontrolvalueslikethis:

<validatecolumn="someColumnName"><values><value>Valuein1strow</value><value>Valuein2ndrow</value><value>Valuein3rdrow</value><value>Valueinxrow</value></values></validate>

WithinJavayoucanpassavariableargumentlisttothevalidatemethodlikethis:

query(dataSource).statement("selectNAMEfromWEEKDAYSwhereNAMELIKE'S%'").validate("NAME","Saturday","Sunday")

Nextexampleshowshowtoworkwithmultiplerowresultsetsandmultiplevaluestoexpectwithinonecolumn:

<sqldatasource="testDataSource"><statement>selectWEEKDAYasDAY,DESCRIPTIONfromWEEK</statement><validatecolumn="DAY"><values><value>Monday</value><value>Tuesday</value><value>Wednesday</value><value>Thursday</value><value>Friday</value><value>@ignore@</value><value>@ignore@</value></values></validate><validatecolumn="DESCRIPTION"><values><value>IhateMondays!</value><value>Tuesdayissportsday</value><value>Themidoftheweek</value><value>Thursdayweplaychess</value><value>Friday,theweekendisnear!</value><value>@ignore@</value><value>@ignore@</value></values>

CitrusReferenceGuide

137Database

Page 138: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</validate></sql>

Forthevalidationofmultiplerowsthe<validate>elementisabletohostalistofcontrolvaluesforacolumn.Asyoucanseefromtheexampleabove,youhavetoaddacontrolvalueforeachrowintheresultset.Thisalsomeansthatwehavetotakecareofthetotalnumberofrows.Fortunatelywecanusetheignoreplaceholder,inordertoskipthevalidationofaspecificrowintheresultset.Functionsandvariablesaresupportedasusual.

ImportantItisimportant,thatthecontrolvaluesaredefinedinthecorrectorder,becausetheyarecomparedoneononewiththeactualresultsetcomingfromdatabasequery.Youmayneedtoadd"orderby"SQLexpressionstogettherightorderofrowsreturned.Ifanyofthevaluesfailsinvalidationorthetotalnumberofrowsisnotequal,thewholeactionwillfailwithrespectivevalidationerrors.

GroovySQLresultsetvalidation

GroovyprovidesgreatsupportforaccessingJavalistobjectsandmaps.AsaJavaSQLresultsetisnothingbutalistofmaprepresentations,whereeachentryinthelistdefinesarowintheresultsetandeachmapentryrepresentsthecolumnsandvalues.SowithGroovy'slistandmapaccesswehavegreatpossibilitiestovalidateaSQLresultset-outofthebox.

XMLDSL

<sqldatasource="testDataSource"><statement>selectIDfromCUSTOMERSwhereNAME='$customerName'</statement><statement>selectORDERTYPE,STATUSfromORDERSwhereID='$orderId'</statement>

<validate-scripttype="groovy">assertrows.size()==2assertrows[0].ID=='1'assertrows[1].STATUS=='inprogress'assertrows[1]==[ORDERTYPE:'SampleOrder',STATUS:'inprogress']</validate-script></sql>

JavaDSLdesigner

query(dataSource).statement("selectORDERTYPE,STATUSfromORDERSwhereID='$orderId'").validateScript("assertrows.size==2;"+

CitrusReferenceGuide

138Database

Page 139: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

"assertrows[0].ID=='1';"+"assertrows[0].STATUS=='inprogress';","groovy");

JavaDSLrunner

query(action->action.dataSource(dataSource).statement("selectORDERTYPE,STATUSfromORDERSwhereID='$orderId'").validateScript("assertrows.size==2;"+"assertrows[0].ID=='1';"+"assertrows[0].STATUS=='inprogress';","groovy"));

AsyoucanseeGroovyprovidesfantasticaccessmethodstotheSQLresultset.Wecanbrowsetheresultsetwithnamedcolumnvaluesandcheckthesizeoftheresultset.Wearealsoabletosearchforanentry,iterateovertheresultsetandhaveotherhelpfuloperations.ForadetaileddescriptionofthelistandmaphandlinginGroovymyadviceforyouistohavealookattheofficialGroovydocumentation.

NoteIngeneralotherscriptlanguagesdoalsosupportthiskindoflistandmapaccess.FornowwejusthaveimplementedtheGroovyscriptsupport,buttheframeworkisreadytoworkwithallothergreatscriptlanguagesoutthere,too(e.g.Scala,Clojure,Fantom,etc.).Soifyouprefertoworkwithanotherlanguagejoinandhelpusimplementthosefeatures.

Saveresultsetvalues

Nowthevalidationofdatabaseentriesisaverypowerfulfeaturebutsometimeswesimplydonotknowthepersistedcontentvalues.Thetestmaywanttoreaddatabaseentriesintotestvariableswithoutvalidation.Citrusisabletodothatwiththefollowingexpressions:

XMLDSL

<sqldatasource="testDataSource"><statement>selectIDfromCUSTOMERSwhereNAME='$customerName'</statement><statement>selectSTATUSfromORDERSwhereID='$orderId'</statement>

<extractcolumn="ID"variable="$customerId"/><extractcolumn="STATUS"variable="$orderStatus"/></sql>

JavaDSLdesigner

CitrusReferenceGuide

139Database

Page 140: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

query(dataSource).statement("selectSTATUSfromORDERSwhereID='$orderId'").extract("STATUS","orderStatus");

JavaDSLrunner

query(action->action.dataSource(dataSource).statement("selectSTATUSfromORDERSwhereID='$orderId'").extract("STATUS","orderStatus"));

Wecansavethedatabasecolumnvaluesdirectlytotestvariables.Ofcourseyoucancombinethevalueextractionwiththenormalcolumnvalidationdescribedearlierinthischapter.Pleasekeepinmindthatwecannotusetheseoperationsonresultsetswithmultiplerows.Citruswillalwaysusethefirstrowinaresultset.

CitrusReferenceGuide

140Database

Page 141: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Sleep

Thisactionshowshowtomakethetestframeworksleepforagivenamountoftime.Theattribute'time'definestheamountoftimetowaitinseconds.Asshowninthenextexampledecimalvaluesaresupportedtoo.Whennowaitingtimeisspecifiedthedefaulttimeof50000millisecondsapplies.

XMLDSL

<testcasename="sleepTest"><actions><sleepseconds="3.5"/>

<sleepmilliseconds="500"/>

<sleep/></actions></testcase>

JavaDSLdesignerandrunner

@CitrusTestpublicvoidsleepTest()sleep(500);//sleep500milliseconds

sleep();//sleepdefaulttime

Whenshouldsomebodyusethisaction?Tousthisactionwasalwaysveryusefulincasethetestneededtowaituntilanapplicationhaddonesomework.Forexampleinsomecasestheapplicationtooksometimetowritesomedataintothedatabase.Wewaitedthenasmallamountoftimeinordertoavoidunnecessarytestfailures,becausethetestframeworksimplyvalidatedthedatabasetooearly.Orasanotherexamplethetestmaywaitagiventimeuntilretrymechanismsaretriggeredinthetestedapplicationandthenproceedwiththetestactions.

CitrusReferenceGuide

141Sleep

Page 142: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Java

ThetestframeworkiswritteninJavaandrunsinsideaJavavirtualmachine.ThefunctionalityofcallingotherJavaobjectsandmethodsinthissameJavaVMthroughJavaReflectionisself-evident.WiththisactionyoucancallanyJavaAPIavailableatruntimethroughthespecifiedJavaclasspath.

Theactionsyntaxlookslikefollows:

<javaclass="com.consol.citrus.test.util.InvocationDummy"><constructor><argumenttype="">TestInvocation</argument></constructor><methodname="invoke"><argumenttype="String[]">1,2</argument></method></java>

<javaclass="com.consol.citrus.test.util.InvocationDummy"><constructor><argumenttype="">TestInvocation</argument></constructor><methodname="invoke"><argumenttype="int">4</argument><argumenttype="String">TestInvocation</argument><argumenttype="boolean">true</argument></method></java>

<javaclass="com.consol.citrus.test.util.InvocationDummy"><methodname="main"><argumenttype="String[]">4,Test,true</argument></method></java>

TheJavaclassisspecifiedbyfullyqualifiedclassname.Constructorargumentsareaddedusingtheelementwithalistofchildelements.Thetypeoftheargumentisdefinedwithintherespectiveattribute"type".BydefaultthetypewouldbeString.

TheinvokedmethodontheJavaobjectissimplyreferencedbyitsname.Methodargumentsdonotbringanythingnewafterknowingtheconstructorargumentdefinition,dothey?.

CitrusReferenceGuide

142Java

Page 143: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Methodargumentssupportdatatypeconversiontoo,evenstringarrays(usefulwhencallingCLIs).Inthethirdactionintheexamplecodeyoucanseethatcolonseparatedstringsareautomaticallyconvertedtostringarrays.

Simpledatatypesaredefinedbytheirname(int,boolean,floatetc.).Besurethattheinvokedmethodandclassconstructorfityourargumentsandviceversa,otherwiseyouwillcauseerrorsatruntime.

BesidesinstantiatingafullynewobjectinstanceforaclasshowaboutreusingabeaninstanceavailableinSpringbeancontainer.SimplyusetherefattributeandrefertoanexistingbeaninSpringapplicationcontext.

<javaref="invocationDummy"><methodname="invoke"><argumenttype="int">4</argument><argumenttype="String">TestInvocation</argument><argumenttype="boolean">true</argument></method></java>

<beanid="invocationDummy"class="com.consol.citrus.test.util.InvocationDummy"/>

ThemethodisinvokedontheSpringbeaninstance.Thisisveryusefulasyoucaninjectotherobjects(e.g.viaAutowiring)totheSpringbeaninstancebeforemethodinvocationintesttakesplace.ThisenablesyoutoexecuteanyJavalogicinsideatestcase.

CitrusReferenceGuide

143Java

Page 144: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Receivetimeout

Insomecasesitmightbenecessarytovalidatethatamessageisnotpresentonadestination.Thismeansthatthisactionexpectsatimeoutwhenreceivingamessagefromanendpointdestination.Forinstancethetesterintendstoensurethatnomessageissenttoacertaindestinationinatimeperiod.Inthatcasethetimeoutwouldnotbeatestabortingerrorbuttheexpectedbehavior.Andincontrasttothenormalbehaviorwhenamessageisreceivedinthetimeperiodthetestwillfailwitherror.

Inordertovalidatesuchatimeoutsituationtheactionshallhelp.Theusageisverysimpleasthefollowingexampleshows:

XMLDSL

<testcasename="receiveJMSTimeoutTest"><actions><expect-timeoutendpoint="myEndpoint"wait="500"/></actions></testcase>

JavaDSLdesigner

@Autowired@Qualifier("myEndpoint")privateEndpointmyEndpoint;

@CitrusTestpublicvoidreceiveTimeoutTest()receiveTimeout(myEndpoint).timeout(500);

JavaDSLrunner

@Autowired@Qualifier("myEndpoint")privateEndpointmyEndpoint;

@CitrusTestpublicvoidreceiveTimeoutTest()receiveTimeout(action->action.endpoint(myEndpoint).timeout(500));

CitrusReferenceGuide

144Timeout

Page 145: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Theactionofferstwoattributes:

endpoint:Referencetoamessageendpointthatwilltrytoreceivemessages.

wait/timeout:Timeperiodtowaitformessagestoarrive

Sometimesyoumaywanttoaddsomeselectoronthetimeoutreceivingaction.Thiswayyoucanveryselectivecheckonamessagetonotbepresentonamessagedestination.Thisispossiblewithdefiningamessageselectoronthetestactionasfollows.

XMLDSL

<expect-timeoutendpoint="myEndpoint"wait="500"><select>MessageId='123456789'<select/><expect-timeout/>

JavaDSLdesigner

@CitrusTestpublicvoidreceiveTimeoutTest()receiveTimeout(myEndpoint).selector("MessageId='123456789'").timeout(500);

JavaDSLrunner

@CitrusTestpublicvoidreceiveTimeoutTest()receiveTimeout(action->action.endpoint(myEndpoint).selector("MessageId='123456789'").timeout(500));

CitrusReferenceGuide

145Timeout

Page 146: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Echo

Theactionprintsmessagestotheconsole/logger.Thisfunctionalityisusefulwhendebuggingtestruns.Theproperty"message"definesthetextthatisprinted.Testermightuseittoprintoutdebugmessagesandvariablesasshownthenextcodeexample:

XMLDSL

<testcasename="echoTest"><variables><variablename="date"value="citrus:currentDate()"/></variables><actions><echo><message>HelloTestFramework</message></echo>

<echo><message>Currentdateis:$date</message></echo></actions></testcase>

JavaDSLdesignerandrunner

@CitrusTestpublicvoidechoTest()variable("date","citrus:currentDate()");

echo("HelloTestFramework");echo("Currentdateis:$date");

Resultontheconsole:

HelloTestFrameworkCurrenttimeis:05.08.2008

CitrusReferenceGuide

146Echo

Page 147: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Stoptime

Timemeasurementduringatestcanbeveryhelpful.Theactioncreatesandmonitorsmultipletimelines.Theactionofferstheattributeidtoidentifyatimeline.Thetestercanofcourseusemorethanonetimelinewithdifferentidssimultaneously.

Readthenextexampleandyouwillunderstandthemixofdifferenttimelines:

XMLDSL

<testcasename="StopTimeTest"><actions><trace-time/>

<trace-timeid="time_line_id"/>

<sleepseconds="3.5"/>

<trace-timeid="time_line_id"/>

<sleepmilliseconds="5000"/>

<trace-time/>

<trace-timeid="time_line_id"/></actions></testcase>

JavaDSL

@CitrusTestpublicvoidstopTimeTest()stopTime();stopTime("time_line_id");sleep(3.5);//dosomethingstopTime("time_line_id");sleep(5000);//dosomethingstopTime();stopTime("time_line_id");

Thetestoutputlookslikefollows:

StartingTimeWatcher:StartingTimeWatcher:time_line_id

CitrusReferenceGuide

147Stoptime

Page 148: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TimeWatchertime_line_idafter3500millisecondsTimeWatcherafter8500secondsTimeWatchertime_line_idafter8500milliseconds

ImportantTimelineidsshouldnotexistastestvariablesbeforetheactioniscalledforthefirsttime.Thiswouldbreakthetimelineinitialization.

NoteIncasenotimelineidisspecifiedtheframeworkwillmeasurethetimeforadefaulttimeline.Toprintoutthecurrentelapsedtimeforatimelineyousimplyhavetoplacethe`actionintotheactionchainagainandagain,usingtherespectivetimelineidentifier.Theelapsedtimewillbeprintedouttotheconsoleeverytime.

Eachtimelineisstoredastestvariableinthetestcase.Bydefaultyouwillhavethefollowingtestvariablessetforeachtimeline:

CITRUS_TIMELINEfirsttimestampoftimelineCITRUS_TIMELINE_VALUElatesttimemeasurementvalue(timepassedsincefirsttimestampinmilliseconds)

Accordingtoyourtimelineidyouwillgetdifferenttestvariablenames.Alsoyoucancustomizethetimevaluesuffix(default:_VALUE):

XMLDSL

<trace-timeid="custom_watcher"suffix="_1st"/><sleep/><trace-timeid="custom_watcher"suffix="_2nd"/>

JavaDSL

@CitrusTeststopTime("custom_watcher","_1st");sleep();stopTime("custom_watcher","_2nd");

Youwillgetfollowingtestvariablesset:

custom_watcherfirsttimestampoftimelinecustom_watcher_1sttimepassedsincestartcustom_watcher_2ndtimepassedsincestart

Ofcourseusingthesamesuffixmultipletimeswilloverwritethetimestampsintestvariables.

CitrusReferenceGuide

148Stoptime

Page 149: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

CitrusReferenceGuide

149Stoptime

Page 150: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Createvariables

Asyouknowvariablesusuallyaredefinedatthebeginningofthetestcase(testcase-variables).Itmightalsobehelpfultoresetexistingvariablesaswellastodefinenewvariablesduringthetest.Theactionisabletodeclarenewvariablesoroverwriteexistingones.

XMLDSL

<testcasename="createVariablesTest"><variables><variablename="myVariable"value="12345"/><variablename="id"value="54321"/></variables><actions><echo><message>Currentvariablevalue:$myVariable</message></echo>

<create-variables><variablename="myVariable"value="$id"/><variablename="newVariable"value="'thisisatest'"/></create-variables>

<echo><message>Currentvariablevalue:$myVariable</message></echo>

<echo><message>Newvariable'newVariable'hasthevalue:$newVariable</message></echo></actions></testcase>

JavaDSLdesignerandrunner

@CitrusTestpublicvoidcreateVariableTest()variable("myVariable","12345");variable("id","54321");

echo("Currentvariablevalue:$myVariable");

createVariable("myVariable","$id");

CitrusReferenceGuide

150Createvariables

Page 151: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

createVariable("newVariable","thisisatest");

echo("Currentvariablevalue:$myVariable");

echo("Newvariable'newVariable'hasthevalue:$newVariable");

NotePleasenotethedifferencebetweenthevariable()methodandthecreateVariable()method.Thefirstinitializesthetestcasewiththetestvariables.Soallvariablesdefinedwiththismethodarevalidfromtheverybeginningofthetest.IncontrarytothatthecreateVariable()isexecutedwithinthetestactionchain.Thenewlycreatedvariablesarethenvalidfortherestofthetest.Trailingactionscanreferencethevariablesasusualwiththevariableexpression.

CitrusReferenceGuide

151Createvariables

Page 152: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Tracevariables

Youalreadyknowtheactionthatprintsmessagestotheconsoleorlogger.Theactionisspeciallydesignedtotraceallcurrentlyvalidtestvariablestotheconsole.Thiswasmainlyusedbyusfordebugreasons.Theusageisquitesimple:

XMLDSL

<testcasename="traceVariablesTest"><variables><variablename="myVariable"value="12345"/><variablename="nextVariable"value="54321"/></variables><actions><trace-variables><variablename="myVariable"/><variablename="nextVariable"/></trace-variables>

<trace-variables/></actions></testcase>

JavaDSLdesignerandrunner

@CitrusTestpublicvoidtraceTest()variable("myVariable","12345");variable("nextVariable","54321");

traceVariables("myVariable","nextVariable");traceVariables();

Simplyaddtheactiontoyouractionchainandallvariableswillbeprintedouttotheconsole.Youareabletodefineaspecialsetofvariablesbyusingthechildelements.Seetheoutputthatwasgeneratedbythetestexampleabove:

CurrentvalueofvariablemyVariable=12345CurrentvalueofvariablenextVariable=54321

CitrusReferenceGuide

152Trace

Page 153: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

CitrusReferenceGuide

153Trace

Page 154: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Transform

The<transform>actiontransformsXMLfragmentswithXSLTinordertoconstructvariousXMLrepresentations.Thetransformationresultisstoredintoatestvariableforfurtherusage.Thepropertyxml-datadefinestheXMLsource,thatisgoingtobetransformed,whilexslt-datadefinestheXSLTtransformationrules.Theattributevariablespecifiesthetargettestvariablewhichreceivesthetransformationresult.ThetestermightusetheactiontotransformXMLmessagesasshowninthenextcodeexample:

XMLDSL

<testcasename="transformTest"><actions><transformvariable="result"><xml-data><![CDATA[<TestRequest><Message>HelloWorld!</Message></TestRequest>]]></xml-data><xslt-data><![CDATA[<xsl:stylesheetversion="1.0"xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:templatematch="/"><html><body><h2>TestRequest</h2><p>Message:<xsl:value-ofselect="TestRequest/Message"/></p></body></html></xsl:template></xsl:stylesheet>]]></xslt-data></transform><echo><message>$result</message></echo></actions></testcase>

Thetransformationaboveresultsto:

CitrusReferenceGuide

154Transform

Page 155: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<html><body><h2>TestRequest</h2><p>Message:HelloWorld!</p></body></html>

IntheexampleweusedCDATAsectionstodefinethetransformationsourceaswellastheXSLtransformationrules.Asusualyoucanalsouseexternalfileresourceshere.Thetransformactionwithexternalfileresourceslookslikefollows:

<transformvariable="result"><xml-resourcefile="classpath:transform-source.xml"/><xslt-resourcefile="classpath:transform.xslt"/></transform>

TheJavaDSLalternativefortransformingdataviaXSTLinCitruslookslikefollows:

JavaDSLdesigner

@CitrusTestpublicvoidtransformTest()transform().source("<TestRequest>"+"<Message>HelloWorld!</Message>"+"</TestRequest>").xslt("<xsl:stylesheetversion=\"1.0\"xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n""<xsl:templatematch=\"/\">\n"+"<html>\n"+"<body>\n"+"<h2>TestRequest</h2>\n"+"<p>Message:<xsl:value-ofselect=\"TestRequest/Message\"/></p>\n""</body>\n"+"</html>\n"+"</xsl:template>\n"+"</xsl:stylesheet>").result("result");

echo("$result");

transform().source(newClassPathResource("com/consol/citrus/actions/transform-source.xml")).xslt(newClassPathResource("com/consol/citrus/actions/transform.xslt")).result("result");

CitrusReferenceGuide

155Transform

Page 156: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

echo("$result");

JavaDSLrunner

@CitrusTestpublicvoidtransformTest()transform(action->action.source("<TestRequest>"+"<Message>HelloWorld!</Message>"+"</TestRequest>").xslt("<xsl:stylesheetversion=\"1.0\"xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n""<xsl:templatematch=\"/\">\n"+"<html>\n"+"<body>\n"+"<h2>TestRequest</h2>\n"+"<p>Message:<xsl:value-ofselect=\"TestRequest/Message\"/></p>\n"+"</body>\n"+"</html>\n"+"</xsl:template>\n"+"</xsl:stylesheet>").result("result"));

echo("$result");

transform(action->action.source(newClassPathResource("com/consol/citrus/actions/transform-source.xml")).xslt(newClassPathResource("com/consol/citrus/actions/transform.xslt")).result("result"));

echo("$result");

Definingmulti-lineStringswithnestedquotesisnofuninJava.Soyoumaywanttouseexternalfileresourcesforyourscriptsasshowninthesecondpartoftheexample.InfactyoucouldalsousescriptlanguageslikeGroovyorScalathathavemuchbettersupportformulti-lineStrings.

CitrusReferenceGuide

156Transform

Page 157: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Groovyscriptexecution

GroovyisanagiledynamiclanguagefortheJavaPlatform.GroovyshipswithalotofverypowerfulfeaturesandfitsperfectlywithJavaasitisbasedonJavaandrunsinsidetheJVM.

TheCitrusGroovysupportmightbetheentranceforyoutowritecustomizedtestactions.YoucaneasilyexecuteGroovycodeinsideatestcase,justlikeanormaltestaction.ThewholetestcontextwithallvariablesisavailabletotheGroovyaction.Thismeanssomeonecanchangevariablevaluesorcreatenewvariablesveryeasily.

Let'shavealookatsomeexamplesinordertounderstandthepossibleGroovycodeinteractionsinCitrus:

XMLDSL

<testcasename="groovyTest"><variables><variablename="time"value="citrus:currentDate()"/></variables><actions><groovy>println'HelloCitrus'</groovy><groovy>println'Thevariableis:$time'</groovy><groovyresource="classpath:com/consol/citrus/script/example.groovy"/></actions></testcase>

JavaDSLdesigner

@CitrusTestpublicvoidgroovyTest()groovy("println'HelloCitrus'");groovy("println'Thevariableis:$time'");

groovy(newClassPathResource("com/consol/citrus/script/example.groovy"));

JavaDSLrunner

@CitrusTest

CitrusReferenceGuide

157Groovy

Page 158: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

publicvoidgroovyTest()groovy(action->action.script("println'HelloCitrus'"));groovy(action->action.script("println'Thevariableis:$time'"));

groovy(action->action.script(newClassPathResource("com/consol/citrus/script/example.groovy"

AsyoucanseeitispossibletowriteGroovycodedirectlyintothetestcase.CitruswillinterpretandexecutetheGroovycodeatruntime.Asusualnestedvariableexpressionsarereplacedwithrespectivevalues.IngeneralthisisdoneinadvancebeforetheGroovycodeisinterpreted.FormorecomplexGroovycodesectionswhichgrowinlinesofcodeyoucanalsoreferenceexternalfileresources.

AfterthisbasicGroovycodeusageinsideatestcasewemightbeinterestedaccessingthewholeTestContext.TheTestContextJavaobjectholdsalltestvariablesandfunctiondefinitionsforthetestcaseandcanbereferencedinGroovycodeviasimplenamingconvention.Justaccesstheobjectreference'context'andyouareabletomanipulatetheTestContext(e.g.settinganewvariablewhichisdirectlyreadyforuseinfollowingtestactions).

XMLDSL

<testcasename="groovyTest"><actions><groovy>context.setVariable("greetingText","HelloCitrus")printlncontext.getVariable("greetingText")</groovy><echo><message>Newvariable:$greetingText</message></echo></actions></testcase>

NoteTheimplicitTestContextaccessthatwasshownintheprevioussampleworkswithadefaultGroovyscripttemplateprovidedbyCitrus.TheGroovycodeyouwriteinthetestcaseisautomaticallysurroundedwithaGroovyscriptwhichtakescareofhandlingtheTestContext.Thedefaulttemplatelookslikefollows:

importcom.consol.citrus.*importcom.consol.citrus.variable.*importcom.consol.citrus.context.TestContextimportcom.consol.citrus.script.GroovyAction.ScriptExecutor

CitrusReferenceGuide

158Groovy

Page 159: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

publicclassGScriptimplementsScriptExecutorpublicvoidexecute(TestContextcontext)@SCRIPTBODY@

Yourcodeisplacedinsubstitutiontothe@SCRIPTBODY@placeholder.NowyoumightunderstandhowCitrushandlesthecontextautomatically.YoucanalsowriteyourownscripttemplatesmakingmoreadvancedusageofotherJavaAPIsandGroovycode.Justaddascripttemplatepathtothetestactionlikethis:

<groovyscript-template="classpath:my-custom-template.groovy">[...]</groovy>

Ontheotherhandyoucandisabletheautomaticscripttemplatewrappinginyouractionatall:

<groovyuse-script-template="false">println'JustusesomeGroovycode'</groovy>

ThenextexampledealswithadvancedGroovycodeandwritingwholeclasses.WewriteanewGroovyclasswhichimplementstheScriptExecutorinterfaceofferedbyCitrus.ThisinterfacedefinesaspecialexecutemethodandprovidesaccesstothewholeTestContextforadvancedtestvariablesaccess.

<testcasename="groovyTest"><variables><variablename="time"value="citrus:currentDate()"/></variables><actions><groovy><![CDATA[importcom.consol.citrus.*importcom.consol.citrus.variable.*importcom.consol.citrus.context.TestContextimportcom.consol.citrus.script.GroovyAction.ScriptExecutor

publicclassGScriptimplementsScriptExecutorpublicvoidexecute(TestContextcontext)printlncontext.getVariable("time")

CitrusReferenceGuide

159Groovy

Page 160: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

]]></groovy></actions></testcase>

ImplementingtheScriptExecutorinterfaceinacustomGroovyclassisapplicableforveryspecialtestcontextmanipulationsasyouareabletoimportanduseotherJavaAPIclassesinthiscode.

CitrusReferenceGuide

160Groovy

Page 161: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Failingthetest

Thefailactionwillgenerateanexceptioninordertoterminatethetestcasewitherror.Thetestcasewillthereforenotbesuccessfulinthereports.

Theusercanspecifyacustomerrormessagefortheexceptioninordertodescribetheerrorcause.Hereisaverysimpleexampletoclarifythesyntax:

XMLDSL

<testcasename="failTest"><actions><failmessage="Testwillfailwithcustommessage"/></actions></testcase>

Testresults:

Executionoftest:failTestfailed!Nestedexceptionis:com.consol.citrus.exceptions.CitrusRuntimeException:Testwillfailwithcustommessage

[...]

CITRUSTESTRESULTS

failTest:failed-Exceptionis:Testwillfailwithcustommessage

Found1testcasestoexecuteSkipped0testcases(0.0%)Executed1testcases,containing3actionsTestsfailed:1(100.0%)Testssuccessfully:0(0.0%)

WhileusingtheJavaDSLtestermightwanttoraisesomeJavaexceptionsinthemiddleofconfiguringthetestcase.Butthisisnotpossibleaswehavetoseparatethedesigntimeandtheexecutiontimeofthetestcase.The@CitrusTestannotatedconfigurationmethodiscalledforbuildingupthewholetestcase.Afterthismethodwasprocessedthetestgetsexecutedinruntimeoththetest.Ifyouspecifyathrowsexceptionstatementintheconfigurationmethodthiswillnotbedoneatruntimebutatdesigntime.ThisiswhyyouhavetousethespecialfailtestactionwhichraisesaJavaexceptionduringtheruntimeofthetest.Thenextexamplewillnotworkasexpected:

CitrusReferenceGuide

161Fail

Page 162: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

JavaDSLdesignerandrunner

@CitrusTestpublicvoidwrongUsageSample()//sometestactions

thrownewValidationException("Thistestshouldfailnow");//doesnotworkasexpected

Thevalidationexceptionaboveisdirectlyraisedbeforethetestisabletostartasthe@CitrusTestannotatedmethoddoesnotrepresentthetestruntime.Insteadofthiswehavetousethefailactionasfollows:

JavaDSLdesignerandrunner

@CitrusTestpublicvoidfailTest()//sometestactions

fail("Thistestshouldfailnow");//failsattestruntimeasexpected

Nowthetestfailsatruntimeasthefailactionisraisedduringthetestexecutionasexpected.

CitrusReferenceGuide

162Fail

Page 163: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Input

Duringthetestcaseexecutionitispossibletoreadsomeuserinputfromthecommandline.Thetestexecutionwillstopandwaitforkeyboardinputsoverthestandardinputstream.Theuserhastotypetheinputandenditwiththereturnkey.

Theuserinputisstoredtotherespectivevariablevalue.

XMLDSL

<testcasename="inputTest"><variables><variablename="userinput"value=""></variable><variablename="userinput1"value=""></variable><variablename="userinput2"value="y"></variable><variablename="userinput3"value="yes"></variable><variablename="userinput4"value=""></variable></variables><actions><input/><echo><message>userinputwas:$userinput</message></echo>

<inputmessage="Nowpressenter:"variable="userinput1"/><echo><message>userinputwas:$userinput1</message></echo>

<inputmessage="Doyouwanttocontinue?"valid-answers="y/n"variable="userinput2"/><echo><message>userinputwas:$userinput2</message></echo>

<inputmessage="Doyouwanttocontinue?"valid-answers="yes/no"variable="userinput3"/><echo><message>userinputwas:$userinput3</message></echo>

<inputvariable="userinput4"/><echo><message>userinputwas:$userinput4</message></echo></actions></testcase>

Asyoucanseetheinputactioniscustomizablewithapromptmessagethatisdisplayedtotheuserandsomevalidanswerpossibilities.Theuserinputisstoredtoatestvariableforfurtheruseinthetestcase.Indetailtheinputactionoffersfollowingattributes:

message->messagedisplayedtotheuser

valid-answers->optionalslashseparatedstringcontainingthepossiblevalidanswers

CitrusReferenceGuide

163Input

Page 164: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

variable->resultvariablenameholdingtheuserinput(default=$userinput)

ThesameactioninJavaDSLnowlooksquitefamiliartousalthoughattributenamingisslightlydifferent:

JavaDSLdesigner

@CitrusTestpublicvoidinputActionTest()variable("userinput","");variable("userinput1","");variable("userinput2","y");variable("userinput3","yes");variable("userinput4","");

input();echo("userinputwas:$userinput");input().message("Nowpressenter:").result("userinput1");echo("userinputwas:$userinput1");input().message("Doyouwanttocontinue?").answers("y","n").result("userinput2");echo("userinputwas:$userinput2");input().message("Doyouwanttocontinue?").answers("yes","no").result("userinput3");echo("userinputwas:$userinput3");input().result("userinput4");echo("userinputwas:$userinput4");

JavaDSLrunner

@CitrusTestpublicvoidinputActionTest()variable("userinput","");variable("userinput1","");variable("userinput2","y");variable("userinput3","yes");variable("userinput4","");

input(action->);echo("userinputwas:$userinput");input(action->action.message("Nowpressenter:").result("userinput1"));echo("userinputwas:$userinput1");input(action->action.message("Doyouwanttocontinue?").answers("y","n").result("userinput2"echo("userinputwas:$userinput2");input(action->action.message("Doyouwanttocontinue?").answers("yes","no").result("userinput3"echo("userinputwas:$userinput3");input(action->action.result("userinput4"));echo("userinputwas:$userinput4");

CitrusReferenceGuide

164Input

Page 165: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Whentheuserinputisrestrictedtoasetofvalidanswerstheinputvalidationofcoursecanfailduetomismatch.Thisisthecasewhentheuserprovidessomeinputnotmatchingthevalidanswersgiven.Inthiscasetheuserisagainaskedtoprovidevalidinput.Thetestactionwillcontinuetoaskforvalidinputuntilavalidanswerisgiven.

NoteUserinputsmaynotfittoautomatictestingintermsofcontinuousintegrationtestingwherenouserispresenttotypeinthecorrectansweroverthekeyboard.Inthiscaseyoucanalwaysskiptheuserinputinadvancebyspecifyingavariablethatmatchestheuserinputvariablename.Astheuserinputvariableisthenalreadypresenttheuserinputismissedoutandthetestproceedsautomatically.

CitrusReferenceGuide

165Input

Page 166: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Load

Youareabletoloadpropertiesfromexternalpropertyfilesandstorethemastestvariables.Theactionwillrequireafileresourceeitherfromclasspathorfilesysteminordertoreadthepropertyvalues.

Letuslookatanexampletogetanideaaboutthisaction:

Contentofload.properties:

username=MickeyMousegreeting.text=HelloTestFramework

XMLDSL

<testcasename="loadPropertiesTest"><actions><load><propertiesfile="file:tests/resources/load.properties"/></load>

<trace-variables/></actions></testcase>

JavaDSLdesignerandrunner

@CitrusTestpublicvoidloadPropertiesTest()load("file:tests/resources/load.properties");

traceVariables();

Output:

Currentvalueofvariableusername=MickeyMouseCurrentvalueofvariablegreeting.text=HelloTestFramework

Theactionwillloadallavailablepropertiesinthefileload.propertiesandstorethemtothetestcaseaslocalvariables.

CitrusReferenceGuide

166Load

Page 167: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ImportantPleasebeawareofthefactthatexistingvariablesareoverwritten!

CitrusReferenceGuide

167Load

Page 168: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Wait

Withthisactionyoucanmakeyourtestwaituntilacertainconditionissatisfied.Theattributesecondsdefinestheamountoftimetowaitinseconds.Youcanalsousethemillisecondsattributeforamorefinegrainedtimevalue.Theattributeintervaldefinestheamountoftimetowaitbetweeneachcheck.Theintervalisalwaysspecifiedasmillisecondtimeinterval.

Ifthecheckdoesnotexceedwithinthedefinedoverallwaitingtimethenthetestexecutionfailswithanappropriateerrormessage.Therearedifferenttypesofconditionstocheck.

http:ThisconditionisbasedonaHttprequestcallonaserverendpoint.CitruswillwaituntiltheHttpresponseisasdefined(e.g.Http200OK).Thisisusefulwhenyouwanttowaitforaservertostart.file:Thisconditionchecksfortheexistenceofafileonthelocalfilesystem.Citruswillwaituntilthefileispresent.message:Thisconditionchecksfortheexistenceofamessageinthelocalmessagestoreofthecurrenttestcase.Citruswillwaituntilthemessagewiththegivennameispresent.

Nextletushavealookatasimpleexample:

XMLDSL

<testcasename="waitTest"><actions><waitseconds="10"interval="2000"><httpurl="http://sample.org/resource"statusCode="200"timeout="2000"/><wait/></actions></testcase>

JavaDSLdesignerandrunner

@CitrusTestpublicvoidwaitTest()waitFor().http("http://sample.org/resource").seconds(10L).interval(2000L);

CitrusReferenceGuide

168Wait

Page 169: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TheexamplewaitsforsomeHttpserverresourcetobeavailablewithHttp200OKresponse.CitruswilluseHEADrequestmethodbydefault.YoucansettherequestmethodwiththemethodattributeontheHttpcondition.

Nextletushavealookatthefileconditionusage:

XMLDSL

<testcasename="waitTest"><actions><waitseconds="10"interval="2000"><filepath="path/to/resource/file.txt"/><wait/></actions></testcase>

JavaDSLdesignerandrunner

@CitrusTestpublicvoidwaitTest()waitFor().file("path/to/resource/file.txt");

Citruschecksforthefiletoexistunderthegivenpath.Onlyifthefileexiststhetestwillcontinuewithfurthertestactions.

Nextletushavealookatthemessageconditionusage:

XMLDSL

<testcasename="waitTest"><actions><waitseconds="10"interval="2000"><messagename="helloRequest"/><wait/></actions></testcase>

JavaDSLdesignerandrunner

@CitrusTestpublicvoidwaitTest()waitFor().message("helloRequest");

CitrusReferenceGuide

169Wait

Page 170: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

CitruschecksforthemessagewiththenamehelloRequestinthelocalmessagestore.Onlyifthemessagewiththegivennameisfoundthetestwillcontinuewithfurthertestactions.Thelocalmessagestoreisautomaticallyfilledwithallexchangedmessages(sendorreceive)inatestcase.Themessagenamesaredefinedintherespectivesendorreceiveoperationsinthetest.

Whenshouldsomebodyusethisaction?Thisactionisveryusefulwhenyouwantyourtesttowaitforacertaineventtooccurbeforecontinuingwiththetestexecution.ForexampleifyouwishthatyourtestwaitsuntilaDockercontainerisstartedorforanapplicationtocreatealogfilebeforecontinuing,thenusethisaction.Youcanalsocreateyourownconditionstatementsandbindittothetestaction.

CitrusReferenceGuide

170Wait

Page 171: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

PurgingJMSdestinations

PurgingJMSdestinationsduringthetestrunisquiteessential.DifferenttestcasescaninfluenceeachotherwhensendingmessagestothesameJMSdestinations.Atestcaseshouldonlyreceivethosemessagesthatactuallybelongtoit.ThereforeitisagoodideatopurgeallJMSqueuedestinationsbetweenthetestcases.ObsoletemessagesthatarestuckinaJMSqueueforsomereasonarethenremovedsothatthefollowingtestcaseisnotoffended.

NoteCitrusprovidesspecialsupportforJMSrelatedfeatures.WehavetoactivatethoseJMSfeaturesinourtestcasebyaddingaspecial"jms"namespaceandschemadefinitionlocationtothetestcaseXML.

<spring:beansxmlns="http://www.citrusframework.org/schema/testcase"xmlns:spring="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:jms="http://www.citrusframework.org/schema/jms/testcase"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/testcasehttp://www.citrusframework.org/schema/testcase/citrus-testcase.xsdhttp://www.citrusframework.org/schema/jms/testcasehttp://www.citrusframework.org/schema/jms/testcase/citrus-jms-testcase.xsd">

[...]

</beans>

NowwearereadytousetheJMSfeaturesinourtestcaseinordertopurgesomeJMSqueues.Thiscanbedonewithfollowingactiondefinition:

XMLDSL

<testcasename="purgeTest"><actions><jms:purge-jms-queues><jms:queuename="Some.JMS.QUEUE.Name"/><jms:queuename="Another.JMS.QUEUE.Name"/><jms:queuename="My.JMS.QUEUE.Name"/></jms:purge-jms-queues>

<jms:purge-jms-queuesconnection-factory="connectionFactory"><jms:queuename="Some.JMS.QUEUE.Name"/><jms:queuename="Another.JMS.QUEUE.Name"/>

CitrusReferenceGuide

171PurgeJMSqueues

Page 172: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<jms:queuename="My.JMS.QUEUE.Name"/></jms:purge-jms-queues></actions></testcase>

Noticethatwehavereferencedthejmsnamespacewhenusingthepurge-jms-queuestestaction.

JavaDSLdesigner

@Autowired@Qualifier("connectionFactory")privateConnectionFactoryconnectionFactory;

@CitrusTestpublicvoidpurgeTest()purgeQueues().queue("Some.JMS.QUEUE.Name").queue("Another.JMS.QUEUE.Name");

purgeQueues(connectionFactory).timeout(150L)//customtimeoutinms.queue("Some.JMS.QUEUE.Name").queue("Another.JMS.QUEUE.Name");

JavaDSLrunner

@Autowired@Qualifier("connectionFactory")privateConnectionFactoryconnectionFactory;

@CitrusTestpublicvoidpurgeTest()purgeQueues(action->action.queue("Some.JMS.QUEUE.Name").queue("Another.JMS.QUEUE.Name"));

purgeQueues(action->action.connectionFactory(connectionFactory).timeout(150L)//customtimeoutinms.queue("Some.JMS.QUEUE.Name").queue("Another.JMS.QUEUE.Name"));

CitrusReferenceGuide

172PurgeJMSqueues

Page 173: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

PurgingtheJMSqueuesineverytestcaseisquiteexhaustingbecauseeverytestcaseneedstodefineapurgingactionattheverybeginningofthetest.Fortunatelythetestsuitedefinitionofferstaskstorunbefore,betweenandafterthetestcaseswhichshouldeaseupthistasksalot.Thetestsuiteoffersaverysimplewaytopurgethedestinationsbetweenthetests.Seetestsuite-before-testformoreinformationaboutthis.

AsyoucanseeinthenextexampleitisquiteeasytospecifyagroupofdestinationsintheSpringconfigurationthatgetpurgedbeforeatestisexecuted.

<citrus:before-testid="purgeBeforeTest"><citrus:actions><jms:purge-jms-queues><jms:queuename="Some.JMS.QUEUE.Name"/><jms:queuename="Another.JMS.QUEUE.Name"/></jms:purge-jms-queues></citrus:actions></citrus:before-test>

NotePleasekeepinmindthattheJMSrelatedconfigurationcomponentsinCitrusbelongtoaseparateXMLnamespacejms:.WehavetoaddthisnamespacedeclarationtoeachtestcaseXMLandSpringbeanXMLconfigurationfileasdescribedattheverybeginningofthissection.

Thesyntaxforpurgingthedestinationsisthesameasweuseditinsidethetestcase.SonowweareabletopurgeJMSdestinationswithgivendestinationnames.ButsometimeswedonotwanttorelyonqueueortopicnamesasweretrievedestinationsoverJNDIforinstance.WecandealwithdestinationscomingfromJNDIlookuplikefollows:

<jee:jndi-lookupid="jmsQueueHelloRequestIn"jndi-name="jms/jmsQueueHelloRequestIn"/><jee:jndi-lookupid="jmsQueueHelloResponseOut"jndi-name="jms/jmsQueueHelloResponseOut"/>

<citrus:before-testid="purgeBeforeTest"><citrus:actions><jms:purge-jms-queues><jms:queueref="jmsQueueHelloRequestIn"/><jms:queueref="jmsQueueHelloResponseOut"/></jms:purge-jms-queues></citrus:actions></citrus:before-test>

CitrusReferenceGuide

173PurgeJMSqueues

Page 174: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Wejustusetheattribute'ref'insteadof'name'andCitrusislookingforabeanreferenceforthatidentifierthatresolvestoaJMSdestination.YoucanusetheJNDIbeanreferencesinsideatestcase,too.

XMLDSL

<testcasename="purgeTest"><actions><jms:purge-jms-queues><jms:queueref="jmsQueueHelloRequestIn"/><jms:queueref="jmsQueueHelloResponseOut"/></jms:purge-jms-queues></actions></testcase>

OfcourseyoucanusequeueobjectreferencesalsoinJavaDSLtestcases.HereweeasilycanuseSpring'sdependencyinjectionwithautowiringtogettheobjectreferencesfromtheIoCcontainer.

JavaDSLdesigner

@Autowired@Qualifier("jmsQueueHelloRequestIn")privateQueuejmsQueueHelloRequestIn;

@Autowired@Qualifier("jmsQueueHelloResponseOut")privateQueuejmsQueueHelloResponseOut;

@CitrusTestpublicvoidpurgeTest()purgeQueues().queue(jmsQueueHelloRequestIn).queue(jmsQueueHelloResponseOut);

JavaDSLrunner

@Autowired@Qualifier("jmsQueueHelloRequestIn")privateQueuejmsQueueHelloRequestIn;

@Autowired@Qualifier("jmsQueueHelloResponseOut")privateQueuejmsQueueHelloResponseOut;

CitrusReferenceGuide

174PurgeJMSqueues

Page 175: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

@CitrusTestpublicvoidpurgeTest()purgeQueues(action->action.queue(jmsQueueHelloRequestIn).queue(jmsQueueHelloResponseOut));

NoteYoucanmixqueuenameandqueueobjectreferencesasyoulikewithinonesinglepurgequeuetestaction.

CitrusReferenceGuide

175PurgeJMSqueues

Page 176: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Purgingmessagechannels

MessagechannelsdefinecentralmessagingdestinationsinCitrus.Thesearenamelyinmemorymessagequeuesholdingmessagesfortestcases.Thesemessagesmaybecomeobsoleteduringatestrun,especiallywhentestcasesfailandstopintheirmessageconsumption.Purgingthesemessagechanneldestinationsisessentialinthesescenariosinordertonotinfluenceupcomingtestcases.Eachtestcaseshouldonlyreceivethosemessagesthatactuallyrefertothetestmodel.Thereforeitisagoodideatopurgeallmessagechanneldestinationsbetweenthetestcases.Obsoletemessagesthatgetstuckinamessagechanneldestinationforsomereasonarethenremovedsothatupcomingtestcasearenotbroken.

Followingactiondefinitionpurgesallmessagesfromalistofmessagechannels:

XMLDSL

<testcasename="purgeChannelTest"><actions><purge-channel><channelname="someChannelName"/><channelname="anotherChannelName"/></purge-channel>

<purge-channel><channelref="someChannel"/><channelref="anotherChannel"/></purge-channel></actions></testcase>

AsyoucanseethetestactionsupportschannelnamesaswellaschannelreferencestoSpringbeaninstances.WhenusingchannelreferencesyourefertotheSpringbeanidornameinyourapplicationcontext.

TheJavaDSLworksquitesimilarasyoucanreadfromnextexamples:

JavaDSLdesigner

@Autowired@Qualifier("channelResolver")privateDestinationResolver<MessageChannel>channelResolver;

@CitrusTestpublicvoidpurgeTest()

CitrusReferenceGuide

176Purgechannels

Page 177: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

purgeChannels().channelResolver(channelResolver).channelNames("ch1","ch2","ch3").channel("ch4");

JavaDSLrunner

@Autowired@Qualifier("channelResolver")privateDestinationResolver<MessageChannel>channelResolver;

@CitrusTestpublicvoidpurgeTest()purgeChannels(action->action.channelResolver(channelResolver).channelNames("ch1","ch2","ch3").channel("ch4"));

Thechannelresolverreferenceisoptional.BydefaultCitruswillautomaticallyuseaSpringapplicationcontextchannelresolversoyoujusthavetousetherespectiveSpringbeannamesthatareconfiguredintheSpringapplicationcontext.Howeversettingacustomchannelresolvermaybeadequateforyouinsomespecialcases.

WhilespeakingofSpringapplicationcontextbeanreferencesthenextexampleusessuchbeanreferencesforchannelstopurge.

JavaDSLdesigner

@Autowired@Qualifier("channel1")privateMessageChannelchannel1;

@Autowired@Qualifier("channel2")privateMessageChannelchannel2;

@Autowired@Qualifier("channel3")privateMessageChannelchannel3;

@CitrusTestpublicvoidpurgeTest()purgeChannels().channels(channel1,channel2).channel(channel3);

CitrusReferenceGuide

177Purgechannels

Page 178: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

JavaDSLrunner

@Autowired@Qualifier("channel1")privateMessageChannelchannel1;

@Autowired@Qualifier("channel2")privateMessageChannelchannel2;

@Autowired@Qualifier("channel3")privateMessageChannelchannel3;

@CitrusTestpublicvoidpurgeTest()purgeChannels(action->action.channels(channel1,channel2).channel(channel3));

Messageselectorsenableyoutoselectivelyremovemessagesfromthedestination.Allmessagesthatpassthemessageselectionlogicgetdeletedtheothermessageswillremainunchangedinsidethechanneldestination.ThemessageselectorisaSpringbeanthatimplementsaspecialmessageselectorinterface.Apossibleimplementationcouldbeaselectordeletingallmessagesthatareolderthanfiveseconds:

importorg.springframework.messaging.Message;importorg.springframework.integration.core.MessageSelector;

publicclassTimeBasedMessageSelectorimplementsMessageSelector

publicbooleanaccept(Message<?>message)if(System.currentTimeMillis()-message.getHeaders().getTimestamp()>5000)returnfalse;elsereturntrue;

NoteThemessageselectorreturnsfalseforthosemessagesthatshouldbedeletedfromthechannel!

CitrusReferenceGuide

178Purgechannels

Page 179: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

YousimplydefinethemessageselectorasanewSpringbeanintheCitrusapplicationcontextandreferenceitinyourtestactionproperty.

<beanid="specialMessageSelector"class="com.consol.citrus.special.TimeBasedMessageSelector"/>

Nowletushavealookathowyoureferencetheselectorinyourtestcase:

XMLDSL

<purge-channelsmessage-selector="specialMessageSelector"><channelname="someChannelName"/><channelname="anotherChannelName"/></purge-channels>

JavaDSLdesigner

@Autowired@Qualifier("specialMessageSelector")privateMessageSelectorspecialMessageSelector;

@CitrusTestpublicvoidpurgeTest()purgeChannels().channelNames("ch1","ch2","ch3").selector(specialMessageSelector);

JavaDSLrunner

@Autowired@Qualifier("specialMessageSelector")privateMessageSelectorspecialMessageSelector;

@CitrusTestpublicvoidpurgeTest()purgeChannels(action->action.channelNames("ch1","ch2","ch3").selector(specialMessageSelector));

CitrusReferenceGuide

179Purgechannels

Page 180: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

IntheexamplesaboveweuseamessageselectorimplementationthatgetsinjectedviaSpringIoCcontainer.

Purgingchannelsineachtestcaseeverytimeisquiteexhaustingbecauseeverytestcaseneedstodefineapurgingactionattheverybeginningofthetest.Amorestraightforwardapproachwouldbetointroducesomepurgingactionwhichisautomaticallyexecutedbeforeeachtest.FortunatelytheCitrustestsuiteoffersaverysimplewaytodothis.Itisdescribedintestsuite-before-test.

Whenusingthespecialactionsequencebeforetestcasesweareabletopurgechanneldestinationseverytimeatestcaseexecutes.SeetheupcomingexampletofindouthowtheactionisdefinedintheSpringconfigurationapplicationcontext.

<citrus:before-testid="purgeBeforeTest"><citrus:actions><purge-channel><channelname="fooChannel"/><channelname="barChannel"/></purge-channel></citrus:actions></citrus:before-test>

Justusethisbefore-testbeanintheSpringbeanapplicationcontextandthepurgechannelactionisactive.Obsoletemessagesthatarewaitingonthemessagechannelsforconsumptionarepurgedbeforethenexttestinlineisexecuted.

TipPurgingmessagechannelsbecomesalsoveryinterestingwhenworkingwithserverinstancesinCitrus.Eachservercomponentautomaticallyhasaninboundmessagechannelwhereincomingmessagesarestoredtointernally.Soifyouneedtocleanupaserverthathasalreadystoredsomeincomingmessagesyoucandothiseasilybypurgingtheinternalmessagechannel.ThemessagechannelfollowsanamingconventionserverName.inboundwhereserverNameistheSpringbeannameoftheCitrusserverendpointcomponent.Ifyoupurgethisinternalchannelinabeforetestnatureyouaresurethatobsoletemessagesonaserverinstancegetpurgedbeforeeachtestisexecuted.

CitrusReferenceGuide

180Purgechannels

Page 181: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Purgingendpoints

Citrusworkswithmessageendpointswhensendingandreceivingmessages.Ingeneralendpointscanalsoqueuemessages.ThisisespeciallythecasewhenusingJMSmessageendpointsoranyserverendpointcomponentinCitrus.Theseareinmemorymessagequeuesholdingmessagesfortestcases.Thesemessagesmaybecomeobsoleteduringatestrun,especiallywhenatestcasethatwouldconsumethemessagesfails.Deletingallmessagesfromamessageendpointisthereforeausefultaskandisessentialinsuchscenariossothatupcomingtestcasesarenotinfluenced.Eachtestcaseshouldonlyreceivethosemessagesthatactuallyrefertothetestmodel.Thereforeitisagoodideatopurgeallmessageendpointdestinationsbetweenthetestcases.Obsoletemessagesthatgetstuckinamessageendpointdestinationforsomereasonarethenremovedsothatupcomingtestcasearenotbroken.

Followingactiondefinitionpurgesallmessagesfromalistofmessageendpoints:

XMLDSL

<testcasename="purgeEndpointTest"><actions><purge-endpoint><endpointname="someEndpointName"/><endpointname="anotherEndpointName"/></purge-endpoint>

<purge-endpoint><endpointref="someEndpoint"/><endpointref="anotherEndpoint"/></purge-endpoint></actions></testcase>

AsyoucanseethetestactionsupportsendpointnamesaswellasendpointreferencestoSpringbeaninstances.WhenusingendpointreferencesyourefertotheSpringbeannameinyourapplicationcontext.

TheJavaDSLworksquitesimilar-havealook:

JavaDSLdesigner

@Autowired@CitrusTestpublicvoidpurgeTest()

CitrusReferenceGuide

181Purgeendpoints

Page 182: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

purgeEndpoints().endpointNames("endpoint1","endpoint2","endpoint3").endpoint("endpoint4");

JavaDSLrunner

@Autowired@CitrusTestpublicvoidpurgeTest()purgeEndpoints(action->action.endpointNames("endpoint1","endpoint2","endpoint3").endpoint("endpoint4"));

WhenusingtheJavaDSLwecaninjectendpointobjectswithSpringbeancontainerIoC.Thenextexampleusessuchbeanreferencesforendpointsinapurgeaction.

JavaDSLdesigner

@Autowired@Qualifier("endpoint1")privateEndpointendpoint1;

@Autowired@Qualifier("endpoint2")privateEndpointendpoint2;

@Autowired@Qualifier("endpoint3")privateEndpointendpoint3;

@CitrusTestpublicvoidpurgeTest()purgeEndpoints().endpoints(endpoint1,endpoint2).endpoint(endpoint3);

JavaDSLrunner

@Autowired@Qualifier("endpoint1")privateEndpointendpoint1;

@Autowired@Qualifier("endpoint2")

CitrusReferenceGuide

182Purgeendpoints

Page 183: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

privateEndpointendpoint2;

@Autowired@Qualifier("endpoint3")privateEndpointendpoint3;

@CitrusTestpublicvoidpurgeTest()purgeEndpoints(action->action.endpoints(endpoint1,endpoint2).endpoint(endpoint3));

Messageselectorsenableyoutoselectivelyremovemessagesfromanendpoint.Allmessagesthatmeetthemessageselectorconditiongetdeletedandtheothermessagesremaininsidetheendpointdestination.ThemessageselectoriseitheranormalStringname-valuerepresentationoramapofkeyvaluepairs:

XMLDSL

<purge-endpoints><selector><value>operation='sayHello'</value></selector><endpointname="someEndpointName"/><endpointname="anotherEndpointName"/></purge-endpoints>

JavaDSLdesigner

@CitrusTestpublicvoidpurgeTest()purgeEndpoints().endpointNames("endpoint1","endpoint2","endpoint3").selector("operation='sayHello'");

JavaDSLrunner

@CitrusTestpublicvoidpurgeTest()purgeEndpoints(action->action.endpointNames("endpoint1","endpoint2","endpoint3").selector("operation='sayHello'"));

CitrusReferenceGuide

183Purgeendpoints

Page 184: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

IntheexamplesaboveweuseaStringtorepresentthemessageselectorexpression.Ingeneralthemessageselectoroperatesonthemessageheader.SofollowingonfromthatweremoveallmessagesselectivelythathaveamessageheaderoperationwithitsvaluesayHello.

Purgingendpointsineachtestcaseeverytimeisquiteexhaustingbecauseeverytestcaseneedstodefineapurgingactionattheverybeginningofthetest.Amorestraightforwardapproachwouldbetointroducesomepurgingactionwhichisautomaticallyexecutedbeforeeachtest.FortunatelytheCitrustestsuiteoffersaverysimplewaytodothis.Itisdescribedintestsuite-before-test.

Whenusingthespecialactionsequencebeforetestcasesweareabletopurgeendpointdestinationseverytimeatestcaseexecutes.SeetheupcomingexampletofindouthowtheactionisdefinedintheSpringconfigurationapplicationcontext.

<citrus:before-testid="purgeBeforeTest"><citrus:actions><purge-endpoint><endpointname="fooEndpoint"/><endpointname="barEndpoint"/></purge-endpoint></citrus:actions></citrus:before-test>

Justusethisbefore-testbeanintheSpringbeanapplicationcontextandthepurgeendpointactionisactive.Obsoletemessagesthatarewaitingonthemessageendpointsforconsumptionarepurgedbeforethenexttestinlineisexecuted.

TipPurgingmessageendpointsbecomesalsoveryinterestingwhenworkingwithserverinstancesinCitrus.Eachservercomponentautomaticallyhasaninboundmessageendpointwhereincomingmessagesarestoredtointernally.Citruswillautomaticallyusethisincomingmessageendpointastargetforthepurgeactionsoyoucanjustusetheserverinstanceasyouknowitfromyourconfigurationinanypurgeaction.

CitrusReferenceGuide

184Purgeendpoints

Page 185: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Assertfailure

CitrustestactionsfailwithJavaexceptionsanderrormessages.Thisgivesyoutheopportunitytoexpectanactiontofailduringtestexecution.YoucansimpleassertaJavaexceptiontobethrownduringexecution.Seetheexampleforanassertactiondefinitioninatestcase:

XMLDSL

<testcasename="assertFailureTest"><actions><assertexception="com.consol.citrus.exceptions.CitrusRuntimeException"message="Unknownvariable$date"><when><echo><message>Currentdateis:$date</message></echo></when></assert></actions></testcase>

JavaDSLdesignerandrunner

@CitrusTestpublicvoidassertTest()assertException().exception(com.consol.citrus.exceptions.CitrusRuntimeException.class).message("Unknownvariable$date").when(echo("Currentdateis:$date"));

NoteNotethattheassertactionrequiresanexception.Incasenoexceptionisthrownbytheembeddedtestactiontheassertionandthetestcasewillfail!

Theassertactionalwayswrapsasingletestaction,whichisthenmonitoredforfailure.Incasethenestedtestactionfailswitherroryoucanvalidatetheerrorinitstypeanderrormessage(optional).Thefailurehastofittheexpectedoneexactlyotherwisetheassertionfailsitself.

ImportantImportanttonoticeisthefactthatassertedexceptionsdonotcausefailureofthetestcase.Asyouexceptthefailuretohappenthetestcontinueswithitsworkoncetheassertionisdonesuccessfully.

CitrusReferenceGuide

185Assert

Page 186: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

CitrusReferenceGuide

186Assert

Page 187: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Catchexceptions

InthepreviouschapterwehaveseenhowtoexpectfailuresinCitruswithassertaction.Nowtheassertactionisdesignedforsingleactionstobemonitoredandforfailurestobeexpectedinanycase.The'catch'actionincontrarycanholdseveralnestedtestactionsandexceptionfailureisoptional.

Thenestedactionsareerrorproofforthechosenexceptiontype.Thismeanspossibleexceptionsarecaughtandignored-thetestcasewillnotfailforthisexceptiontype.Butonlyforthisparticularexceptiontype!Otherexceptiontypesthatoccurduringexecutiondocausethetesttofailasusual.

XMLDSL

<testcasename="catchExceptionTest"><actions><catchexception="com.consol.citrus.exceptions.CitrusRuntimeException"><echo><message>Currentdateis:$date</message></echo></catch></actions></testcase>

JavaDSLdesignerandrunner

@CitrusTestpublicvoidcatchTest()catchException().exception(CitrusRuntimeException.class).when(echo("Currentdateis:$date"));

ImportantNotethatthereisnovalidationavailableinacatchblock.Socatchingexceptionsisjusttomakeatestmorestabletowardserrorsthatcanoccur.Thecaughtexceptiondoesnotcauseanyfailureinthetest.Thetestcasemaycontinuewithexecutionasiftherewasnotfailure.Alsonoticethatthecatchactionisalsohappywhennoexceptionatallisraised.Incontrarytothattheassertactionrequirestheexceptionandanassertactionisfailinginpositiveprocessing.

Catchingexceptionslikethismayonlyfittoveryerrorproneactionblockswherefailuresdonotharmthetestcasesuccess.Otherwiseafailureinatestactionshouldalwaysreflecttothewholetestcasetofailwitherrors.

CitrusReferenceGuide

187Catch

Page 188: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

NoteJavadevelopersmightaskwhynotusetry-catchJavablockinstead?Theanswerissimpleyetveryimportanttounderstand.ThetestmethodiscalledbytheJavaDSLtestcasebuilderforbuildingtheCitrustest.Thiscanbereferredtoasthedesigntimeofthetest.Afterthebuildingtestmethodwasprocessedthetestgetsexecuted,whichcanbecalledtheruntimeofthetest.Thismeansthatatry-catchblockwithinthedesigntimemethodwillneverperformduringthetestrun.TheonlyreliablewaytoaddthecatchcapabilitytothetestaspartofthetestcaseruntimeistousetheCitrustestactionwhichgetsexecutedduringtestruntime.

CitrusReferenceGuide

188Catch

Page 189: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

RunningApacheAntbuildtargets

Theactionloadsabuild.xmlAntfileandexecutesoneormoretargetsintheAntproject.ThetargetisexecutedwithoptionalbuildpropertiespassedtotheAntrun.TheAntbuildoutputisloggedwithCitrusloggerandthetestcasesuccessisboundtotheAntbuildsuccess.ThismeansincasetheAntbuildfailsforsomereasonthetestcasewillalsofailwithbuildexceptionaccordingly.

SeethisbasicAntrunexampletoseehowitworkswithinyourtestcase:

XMLDSL

<testcasename="AntRunTest"><variables><variablename="today"value="citrus:currentDate()"/></variables><actions><antbuild-file="classpath:com/consol/citrus/actions/build.xml"><executetarget="sayHello"/><properties><propertyname="date"value="$today"/><propertyname="welcomeText"value="Hello!"/></properties></ant></actions></testcase>

JavaDSLdesigner

@CitrusTestpublicvoidantRunTest()variable("today","citrus:currentDate()");

antrun("classpath:com/consol/citrus/actions/build.xml").target("sayHello").property("date","$today").property("welcomeText","$Hello!");

JavaDSLrunner

@CitrusTestpublicvoidantRunTest()variable("today","citrus:currentDate()");

CitrusReferenceGuide

189Antrun

Page 190: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

antrun(action->action.buildFilePath("classpath:com/consol/citrus/actions/build.xml").target("sayHello").property("date","$today").property("welcomeText","$Hello!"));

Therespectivebuild.xmlAntfilemustprovidethetargettocall.Forexample:

<projectname="citrus-build"default="sayHello"><propertyname="welcomeText"value="WelcometoCitrus!"></property>

<targetname="sayHello"><echomessage="$welcomeText-Todayis$date"></echo></target>

<targetname="sayGoodbye"><echomessage="Goodbyeeverybody!"></echo></target></project>

AsyoucanseeyoucanpasscustombuildpropertiestotheAntbuildexecution.ExistingAntbuildpropertiesarereplacedandyoucanusethepropertiesinyourbuildfileasusual.

Youcanalsocallmultipletargetswithinonesinglebuildrunbyusingacommaseparatedlistoftargetnames:

XMLDSL

<testcasename="AntRunTest"><variables><variablename="today"value="citrus:currentDate()"/></variables><actions><antbuild-file="classpath:com/consol/citrus/actions/build.xml"><executetargets="sayHello,sayGoodbye"/><properties><propertyname="date"value="$today"/></properties></ant></actions></testcase>

JavaDSLdesigner

CitrusReferenceGuide

190Antrun

Page 191: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

@CitrusTestpublicvoidantRunTest()variable("today","citrus:currentDate()");

antrun("classpath:com/consol/citrus/actions/build.xml").targets("sayHello","sayGoodbye").property("date","$today");

JavaDSLrunner

@CitrusTestpublicvoidantRunTest()variable("today","citrus:currentDate()");

antrun(action->action.buildFilePath("classpath:com/consol/citrus/actions/build.xml").targets("sayHello","sayGoodbye").property("date","$today"));

Thebuildpropertiescanliveinexternalfileresourceasanalternativetotheinlinepropertydefinitions.Youjusthavetousetherespectivefileresourcepathandallnestedpropertiesgetloadedasbuildproperties.

Inadditiontothatyoucanalsodefineacustombuildlistener.ThebuildlistenermustimplementtheAntAPIinterfaceorg.apache.tools.ant.BuildListener.DuringtheAntbuildrunthebuildlisteneriscalledwithseveralcallbackmethods(e.g.buildStarted(),buildFinished(),targetStarted(),targetFinished(),...).ThisishowyoucanaddadditionallogictotheAntbuildrunfromCitrus.Acustombuildlistenercouldmanagethefailstateofyourtestcase,inparticularbyraisingsomeexceptionforcingthetestcasetofailaccordingly.

XMLDSL

<testcasename="AntRunTest"><actions><antbuild-file="classpath:com/consol/citrus/actions/build.xml"build-listener="customBuildListener"><executetarget="sayHello"/><propertiesfile="classpath:com/consol/citrus/actions/build.properties"/></ant></actions></testcase>

CitrusReferenceGuide

191Antrun

Page 192: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

JavaDSLdesigner

@AutowiredprivateBuildListenercustomBuildListener;

@CitrusTestpublicvoidantRunTest()antrun("classpath:com/consol/citrus/actions/build.xml").target("sayHello").propertyFile("classpath:com/consol/citrus/actions/build.properties").listener(customBuildListener);

JavaDSLrunner

@AutowiredprivateBuildListenercustomBuildListener;

@CitrusTestpublicvoidantRunTest()antrun(action->action.buildFilePath("classpath:com/consol/citrus/actions/build.xml").target("sayHello").propertyFile("classpath:com/consol/citrus/actions/build.properties").listener(customBuildListener));

ThecustomBuildListenerusedintheexampleaboveshouldreferenceaSpringbeanintheCitrusapplicationcontext.Thebeanimplementstheinterfaceorg.apache.tools.ant.BuildListenerandcontrolstheAntbuildrun.

CitrusReferenceGuide

192Antrun

Page 193: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Start/Stopserverinstances

Citrusisworkingwithservercomponentsthatarestartedandstoppedwithinatestrun.ThiscanbeaHttpserverorsomeSMTPmailserverforinstance.UsuallytheCitrusservercomponentsareautomaticallystartedwhenCitrusisstartingandrespectivelystoppedwhenCitrusisshuttingdown.Sometimesitmightbehelpfultoexplicitlystartandstopaserverinstancewithinyourtestcase.Hereyoucanusespecialstartandstoptestactionsinsideyourtest.Thisisagoodwaytotestdowntimescenariosofinterfacepartnerswithrespectiveerrorhandlingwhenconnectionstoserversarelost

Letmeexplainwithasimplesampletestcase:

XMLDSL

<testcasename="sleepTest"><actions><startserver="myMailServer"/>

<sleep/>

<stopserver="myMailServer"/></actions></testcase>

ThestartandstopservertestactionreceiveaservernamewhichreferencesaSpringbeancomponentoftypecom.consol.citrus.server.ServerinyourbasicSpringapplicationcontext.Theserverinstanceisstartedorstoppedwithinthetestcase.Asyoucanseeinthenextlistingwecanalsostartandstopmultipleserverinstanceswithinasingletestaction.

<testcasename="sleepTest"><actions><start><servers><servername="myMailServer"/><servername="myFtpServer"/></servers></start>

<sleep/>

<stop><servers><servername="myMailServer"/>

CitrusReferenceGuide

193Manageserver

Page 194: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<servername="myFtpServer"/></servers></stop></actions></testcase>

WhenusingtheJavaDSLthebestwaytoreferenceaserverinstanceistoautowiretheSpringbeanviadependencyinjection.TheSpringframeworktakescaseoninjectingtheproperSpringbeancomponentdefinedintheSPringapplicationcontext.ThiswayyoucaneasilystartandstopserverinstanceswithinJavaDSLtestcases.

JavaDSLdesignerandrunner

@Autowired@Qualifier("myFtpServer")privateFtpServermyFtpServer;

@CitrusTestpublicvoidstartStopServerTest()start(myFtpServer);

sleep();

stop(myFtpServer);

NoteStartingandstoppingserverinstancesisasynchronoustestaction.Thismeansthatyourtestcaseiswaitingfortheservertostartbeforeothertestactionstakeplace.Startuptimesandshutdownofserverinstancesmaydelayyourtestaccordingly.

AsyoucanseestartingandstoppingCitrusserverinstancesisveryeasy.Youcanalsowriteyourownserverimplementationsbyimplementingtheinterfacecom.consol.citrus.server.Server.Allcustomserverimplementationscanthenbestartedandstoppedduringatestcase.

CitrusReferenceGuide

194Manageserver

Page 195: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

StopTimer

Theactioncanbeusedforstoppingeitheraspecifictimer(containers-timer)oralltimersrunningwithinatest.Thisactionisusefulwhentimersarestartedinthebackground(usingparallelorfork=true)andyouwishtostopthesetimersattheendofthetest.Someexamplesofusingthisactionareprovidedbelow:

XMLDSL

<testcasename="timerTest"><actions><timerid="forkedTimer"fork="true"><sleepmilliseconds="50"/></timer>

<timerfork="true"><sleepmilliseconds="50"/></timer>

<timerrepeatCount="5"><sleepmilliseconds="50"/></timer>

<stop-timertimerId="forkedTimer"/></actions><finally><stop-timer/></finally></testcase>

JavaDSLdesignerandrunner

@CitrusTestpublicvoidtimerTest()

timer().timerId("forkedTimer").fork(true).actions(sleep(50L));

timer().fork(true).actions(sleep(50L));

CitrusReferenceGuide

195Stoptimer

Page 196: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

timer().repeatCount(5).actions(sleep(50L));

stopTimer("forkedTimer")

doFinally().actions(stopTimer());

Intheaboveexample3timersarestarted,thefirst2inthebackgroundandthethirdinthetestexecutionthread.Timer#3hasarepeatCountsetto5soitwillterminateautomaticallyafter5runs.Timer#1and#2howeverhavenorepeatCountsetsotheywillexecuteuntiltheyaretoldtostop.

Timer#1isstoppedexplicitlyusingthefirststopTimeraction.HerethestopTimeractionincludesthenameofthetimertostop.Thisisconvenientwhenyouwishtoterminateaspecifictimer.HoweversincenotimerIdwassetfortimer#2,youcanterminatethis(andallothertimers)usingthe'stopTimer'actionwithnoexplicittimerIdset.

CitrusReferenceGuide

196Stoptimer

Page 197: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Includingcustomtestactions

Nowwehavealookattheopportunitytoaddcustomtestactionstothetestcaseflow.Letusstartthissectionwithanexample:

XMLDSL

<testcasename="ActionReferenceTest"><actions><actionreference="cleanUpDatabase"/><actionreference="mySpecialAction"/></actions></testcase>

ThegenericelementreferencesSpringbeansthatimplementtheJavainterfacecom.consol.citrus.TestAction.ThisisaveryfastwaytoaddyourownactionimplementationstoaCitrustestcase.ThiswayyoucaneasilyimplementyourownactionsinJavaandincludethemintothetestcase.

Intheexampleabovethecalledactionsarespecialdatabasecleanupimplementations.TheactionsaredefinedasSpringbeansintheCitrusconfigurationandgetreferencedbytheirbeannameorid.

<beanid="cleanUpDatabase"class="my.domain.citrus.actions.SpecialDatabaseCleanupAction"><propertyname="dataSource"ref="testDataSource"/></bean>

TheSpringapplicationcontextholdsyourcustombeanimplementations.YoucansetpropertiesandusethefullSpringpowerwhileimplementingyourcustomtestactioninJava.LetushavealookonhowsuchaJavaclassmaylooklike.

importcom.consol.citrus.actions.AbstractTestAction;importcom.consol.citrus.context.TestContext;

publicclassSpecialDatabaseCleanupActionextendsAbstractTestAction

@AutowiredprivateDataSourcedataSource;

@OverridepublicvoiddoExecute(TestContextcontext)JdbcTemplatejdbcTemplate=newJdbcTemplate(dataSource);

CitrusReferenceGuide

197Genericaction

Page 198: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

jdbcTemplate.execute("...");

AllyouneedtodoinyourJavaclassistoimplementtheCitruscom.consol.citrus.TestActioninterface.Theabstractclasscom.consol.citrus.actions.AbstractTestActionmayhelpyoutostartwithyourcustomtestactionimplementationasitprovidesbasicmethodimplementationssoyoujusthavetoimplementthedoExecute()method.

WhenusingtheJavatestcaseDSLyouarealsoquitecomfortablewithincludingyourcustomtestactions.

JavaDSLdesignerandrunner

@AutowiredprivateSpecialDatabaseCleanupActioncleanUpDatabaseAction;

@CitrusTestpublicvoidgenericActionTest()echo("Nowlet'sincludeourspecialtestaction");

action(cleanUpDatabaseAction);

echo("That'sit!");

Usinganonymousclassimplementationsisalsopossible.

JavaDSLdesignerandrunner

@CitrusTestpublicvoidgenericActionTest()echo("Nowlet'scallourspecialtestactionanonymously");

action(newAbstractTestAction()publicvoiddoExecute(TestContextcontext)//dosomething);

echo("That'sit!");

CitrusReferenceGuide

198Genericaction

Page 199: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

CitrusReferenceGuide

199Genericaction

Page 200: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TemplatesTemplatesgroupactionsequencestoalogicalunit.Youcanthinkoftemplatesasreusablecomponentsthatareusedinseveraltests.Themaintenanceismuchmoreeffectivebecausethetemplatesarereferencedseveraltimes.

Thetemplatealwayshasauniquename.Insideatestcasewecallthetemplatebythisuniquename.Havealookatafirstexample:

<templatename="doCreateVariables"><create-variables><variablename="var"value="123456789"/></create-variables>

<call-templatename="doTraceVariables"/></template>

<templatename="doTraceVariables"><echo><message>Currenttimeis:$time</message></echo>

<trace-variables/></template>

Thecodeexampleabovedescribestwotemplatedefinitions.Templatesholdasequenceoftestactionsorcallothertemplatesthemselvesasseenintheexampleabove.

NoteTheactioncallsothertemplatesbytheirname.ThecalledtemplatenotnecessarilyhastobelocatedinthesametestcaseXMLfile.ThetemplatemightbedefinedinaseparateXMLfileotherthanthetestcaseitself:

XMLDSL

<testcasename="templateTest"><variables><variablename="myTime"value="citrus:currentDate()"/></variables><actions><call-templatename="doCreateVariables"/>

<call-templatename="doTraceVariables"><parametername="time"value="$myTime">

CitrusReferenceGuide

200Templates

Page 201: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</call-template></actions></testcase>

JavaDSLdesigner

@CitrusTestpublicvoidtemplateTest()variable("myTime","citrus:currentDate()");

applyTemplate("doCreateVariables");

applyTemplate("doTraceVariables").parameter("time","$myTime");

JavaDSLrunner

@CitrusTestpublicvoidtemplateTest()variable("myTime","citrus:currentDate()");

applyTemplate(template->template.name("doCreateVariables"));

applyTemplate(template->template.name("doTraceVariables").parameter("time","$myTime"));

Thereisanopenquestionwhendealingwithtemplatesthataredefinedsomewhereelseoutsidethetestcase.Howtohandlevariables?Atemplatesmayusedifferentvariablenamesthenthetestandviceversa.Nodoubtthetemplatewillfailassoonasspecialvariableswithrespectivevaluesarenotpresent.Unknownvariablescausethetemplateandthewholetesttofailwitherrors.

Soafirstapproachwouldbetoharmonizevariableusageacrosstemplatesandtestcases,sothattemplatesandtestcasesdousethesamevariablenaming.Butthisapproachmightleadtohighcalibrationeffort.Thereforetemplatessupportparameterstosolvethisproblem.Whenatemplateiscalledthecallingactorisabletosetsomeparameters.Letusdiscussanexampleforthisissue.

Thetemplate"doDateCoversion"inthenextsampleusesthevariable$date.Thecallingtestcasecansetthisvariableasaparameterwithoutactuallydeclaringthevariableinthetestitself:

CitrusReferenceGuide

201Templates

Page 202: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<call-templatename="doDateCoversion"><parametername="date"value="$sampleDate"></call-template>

ThevariablesampleDateisalreadypresentinthetestcaseandgetstranslatedintothedateparameter.Followingfromthatthetemplateworksfinealthoughtestandtemplatedoworkondifferentvariablenamings.

Withtemplateparametersyouareabletosolvethecalibrationeffortwhenworkingwithtemplatesandvariables.Itisalwaysagoodideatochecktheusedvariables/parametersinsideatemplatewhencallingit.Theremightbeavariablethatisnotdeclaredyetinsideyourtest.Soyouneedtodefinethisvalueasaparameter.

TemplateparametersmaycontainmorecomplexvalueslikeXMLfragments.Thecall-templateactionoffersfollowingCDATAvariationfordefiningcomplexparametervalues:

<call-templatename="printXMLPayload"><parametername="payload"><value><![CDATA[<HelloRequestxmlns="http://www.consol.de/schemas/samples/sayHello.xsd"><Text>HelloSouth$var</Text></HelloRequest>]]></value></parameter></call-template>

ImportantWhenatemplateworksonvariablevaluesandparameterschangestothesevariableswillautomaticallyaffectthevariablesinthewholetest.Soifyouchangeavariable'svalueinsideatemplateandthevariableisdefinedinsidethetestcasethechangeswillaffectthevariableinaglobalcontext.Wehavetobecarefulwiththiswhenexecutingatemplateseveraltimesinatest,especiallyincombinationwithparallelcontainers(seecontainers-parallel).

<parallel><call-templatename="print"><parametername="param1"value="1"/><parametername="param2"value="HelloEurope"/></call-template><call-templatename="print"><parametername="param1"value="2"/><parametername="param2"value="HelloAsia"/></call-template>

CitrusReferenceGuide

202Templates

Page 203: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<call-templatename="print"><parametername="param1"value="3"/><parametername="param2"value="HelloAfrica"/></call-template></parallel>

Inthelistingaboveatemplateprintiscalledseveraltimesinaparallelcontainer.Theparametervalueswillbehandledinaglobalcontext,soitisquitelikelytohappenthatthetemplateinstancesinfluenceeachotherduringexecution.Wemightgetsuchprintmessages:

2.HelloEurope2.HelloAfrica3.HelloAfrica

Indexparametersdonotfitandthemessage'HelloAsia'iscompletelygone.Thisisbecausetemplatesoverwriteparameterstoeachotherastheyareexecutedinparallelatthesametime.Toavoidthisbehaviorweneedtotellthetemplatethatitshouldhandleparametersaswellasvariablesinalocalcontext.Thiswillenforcethateachtemplateinstanceisworkingonadedicatedlocalcontext.Seetheglobal-contextattributethatissettofalseinthisexample:

<templatename="print"global-context="false"><echo><message>$param1.$param2</message></echo></template>

Afterthattemplateinstanceswon'tinfluenceeachotheranymore.Butnoticethatvariablechangesinsidethetemplatethendonotaffectthetestcaseneither.

CitrusReferenceGuide

203Templates

Page 204: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TestbehaviorsTestbehaviorscombineactionsequencestoalogicalunit.ThebehaviordefinesasetoftestactionsthatcanbeappliedtoaJavaDSLtestcase.Followingfromthatyoucansaythatbehaviorsarereusabletestactiontemplates.Themaintenanceismuchmoreeffectivewhenyoureusebasictestactionsinmanytestcases.

ThebehaviorisaseparateJavaDSLclasswithasingleapplymethodthatconfiguresthetestactions.Havealookatthisfirstexample:

JavaDSL

publicclassFooBehaviorextendsAbstractTestBehaviorpublicvoidapply()variable("foo","test");

echo("fooBehavior");

publicclassBarBehaviorextendsAbstractTestBehaviorpublicvoidapply()variable("bar","test");

echo("barBehavior");

AsyoucanseethebehaviorclassisabletousetheCitrusJavaDSLasusual.Eachbehaviorisabletodefinetestvariablesandactions.Inatestcaseyoucanapplythebehaviorsasfollows:

JavaDSL

@CitrusTestpublicvoidbehaviorTest()variable("myTime","citrus:currentDate()");

FooBehaviorfooBehavior=newFooBehavior();applyBehavior(fooBehavior);

applyBehavior(newBarBehavior());

applyBehavior(fooBehavior);

CitrusReferenceGuide

204Testbehaviors

Page 205: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Whendealingwithbehaviorstestactionsaredefinedsomewhereoutsidethetestcase.Howdowehandletestvariables?Abehaviormayusedifferentvariablenamesthenthetestandviceversa.Nodoubtthebehaviorwillfailassoonasspecialvariableswithrespectivevaluesarenotpresent.Unknownvariablescausethebehaviorandthewholetesttofailwitherrors.

Soagoodapproachwouldbetoharmonizevariableusageacrossbehaviorsandtestcases,sothattemplatesandtestcasesdousethesamevariablenaming.Thebehaviorautomaticallyknowsallvariablesinthetestcase.Andalltestvariablescreatedinsidethebehaviorarevisibletothetestcaseafterapplying.

ImportantWhenabehaviorchangesvariablesthiswillautomaticallyaffectthevariablesinthewholetest.Soifyouchangeavariable'svalueinsideabehaviorandthevariableisdefinedinsidethetestcasethechangeswillaffectthevariableinaglobaltestcontext.Thismeanswehavetobecarefulwhenexecutingabehaviorseveraltimesinatest,especiallyincombinationwithparallelcontainers(seecontainers-parallel).

Behaviortypes

ThetestcaseinJavaisabletofolloweitherdesignerorrunnerstrategies.Thismeanswealsohavetwodifferentbehaviortypesfordesignerandrunnerrespectively.Thebehaviorsarelocatedinseparatepackages

com.consol.citrus.dsl.design.AbstractTestBehaviorcom.consol.citrus.dsl.runner.AbstractTestBehavior

Decidewhichbasebehavioryouwanttoextendfromaccordingtoyourtestcasenature.

CitrusReferenceGuide

205Testbehaviors

Page 206: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ContainersSimilartotemplatesacontainerelementholdsonetomanytestactions.Incontrasttothetemplatethecontainerappearsdirectlyinsidethetestcaseactionchain,meaningthatthecontainerisnotreferencedbymorethanonetestcase.

Containersexecutetheembeddedtestactionsinspecificlogic.Thiscanbeanexecutioniniterationforinstance.Combinedifferentcontainerswitheachotherandyouwillbeabletogenerateverypowerfulhierarchicalstructuresinordertocreateacomplexexecutionlogic.Inthefollowingsectionssomepredefinedcontainersaredescribed.

CitrusReferenceGuide

206Containers

Page 207: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Sequential

Thesequentialcontainerexecutestheembeddedtestactionsinstrictsequence.Readersnowmightsearchforthedifferencetothenormalactionchainthatisspecifiedinsidethetestcase.Theactualpowerofsequentialcontainersdoesshowonlyincombinationwithothercontainerslikeiterationsandparallels.Wewillseethislaterwhenhandlingthesecontainers.

Fornowthesequentialcontainerseemsnotverysensational-onemightsayboring-becauseitsimplygroupsapairoftestactionstosequentialexecution.

XMLDSL

<testcasename="sequentialTest"><actions><sequential><trace-time/><sleep/><echo><message>HalloTestFramework</message></echo><trace-time/></sequential></actions></testcase>

JavaDSLdesignerandrunner

@CitrusTestpublicvoidsequentialTest()sequential().actions(stopTime(),sleep(1.0),echo("HelloCitrus"),stopTime());

CitrusReferenceGuide

207Sequential

Page 208: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Conditional

Nowwedealwithconditionalexecutionsoftestactions.Nestedactionsinsideaconditionalcontainerareexecutedonlyincaseabooleandexpressionevaluatestotrue.Otherwisethecontainerexecutionisnotperformedatall.

Seesomeexampletofindouthowitworkswiththeconditionalexpressionstring.

XMLDSL

<testcasename="conditionalTest"><variables><variablename="index"value="5"/><variablename="shouldSleep"value="true"/></variables>

<actions><conditionalexpression="$index=5"><sleepseconds="10"/></conditional>

<conditionalexpression="$shouldSleep"><sleepseconds="10"/></conditional>

<conditionalexpression="@assertThat('$shouldSleep','anyOf(is(true),isEmptyString())')@"<sleepseconds="10"/></conditional></actions></testcase>

JavaDSLdesignerandrunner

@CitrusTestpublicvoidconditionalTest()variable("index",5);variable("shouldSleep",true);

conditional().when("$index=5")).actions(sleep(10000L));

conditional().when("$shouldSleep")).actions(sleep(10000L)

CitrusReferenceGuide

208Conditional

Page 209: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

);

conditional().when("$shouldSleep",anyOf(is("true"),isEmptyString())).actions(sleep(10000L));

Thenestedsleepactionisexecutedincasethevariable$indexisequaltothevalue'5'.Thisconditionalexecutionoftestactionsisusefulwhendealingwithdifferenttestenvironmentssuchasdifferentoperatingsystemsforinstance.Theconditionalcontaineralsosupportsexpressionsthatevaluatetothecharactersequence"true"or"false"asshowninthe$shouldSleepexample.

ThelastconditionalcontainerintheexampleabovemakesuseofHamcrestmatchers.Thematcherevaluatestotrueoffalseandbasedonthatthecontaineractionsareexecutedorskipped.TheHamcrestmatchersareverypowerfulwhenitcomestoevaluationofmultipleconditionsatatime.

CitrusReferenceGuide

209Conditional

Page 210: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Parallel

Parallelcontainersexecutetheembeddedtestactionsconcurrenttoeachother.EveryactioninthiscontainerwillbeexecutedinaseparateJavaThread.Followingexampleshouldclarifytheusage:

XMLDSL

<testcasename="parallelTest"><actions><parallel><sleep/>

<sequential><sleep/><echo><message>1</message></echo></sequential>

<echo><message>2</message></echo>

<echo><message>3</message></echo>

<iteratecondition="ilt=5"index="i"><echo><message>10</message></echo></iterate></parallel></actions></testcase>

JavaDSLdesignerandrunner

@CitrusTestpublicvoidparalletTest()parallel().actions(sleep(),sequential().actions(sleep(),echo("1")

CitrusReferenceGuide

210Parallel

Page 211: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

),echo("2"),echo("3"),iterate().condition("ilt=5").index("i")).actions(echo("10")));

Sothenormaltestactionprocessingwouldbetoexecuteoneactionafteranother.Asthefirstactionisasleepoffiveseconds,thewholetestprocessingwouldstopandwaitfor5seconds.Thingsaredifferentinsidetheparallelcontainer.Herethedescendingtestactionswillnotwaitbutexecuteatthesametime.

NoteNotethatcontainerscaneasilywrapothercontainers.Theexampleshowsasimplecombinationofsequentialandparallelcontainersthatwillarchiveacomplexexecutionlogic.Actionsinsidethesequentialcontainerwillexecuteoneafteranother.Butactionsinparallelwillbeexecutedatthesametime.

CitrusReferenceGuide

211Parallel

Page 212: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Iterate

Iterationsareverypowerfulelementswhendescribingcomplexlogic.Thecontainerexecutestheembeddedactionsseveraltimes.Thecontainerwillcontinuewithloopingaslongasthedefinedbreakingconditionstringevaluatestotrue.Incasetheconditionevaluatestofalsetheiterationwillbreakanfinishexecution.

XMLDSL

<testcasename="iterateTest"><actions><iterateindex="i"condition="ilt5"><echo><message>indexis:$i</message></echo></iterate></actions></testcase>

JavaDSLdesignerandrunner

@CitrusTestpublicvoiditerateTest()iterate().condition("ilt5").index("i")).actions(echo("indexis:$i"));

Theattribute"index"automaticallydefinesanewvariablethatholdstheactualloopindexstartingat"1".Thisindexvariableisavailableasanormalvariableinsidetheiteratecontainer.Thereforeitispossibletoprintouttheactualloopindexintheechoactionasshownintheaboveexample.

Theconditionstringismandatoryanddescribestheactualendoftheloop.Initeratecontainerstheloopwillbreakincasetheconditionevaluatestofalse.

TheconditionstringcanbeanyBooleanexpressionandsupportsseveraloperators:

lt(lowerthan)

lt=(lowerthanequals)

gt(greaterthan)

CitrusReferenceGuide

212Iterate

Page 213: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

gt=(greaterthanequals)

=(equals)

and(logicalcombiningoftwoBooleanvalues)

or(logicalcombiningoftwoBooleanvalues)

()(brackets)

ImportantItisveryimportanttonoticethattheconditionisevaluatedbeforetheveryfirstiterationtakesplace.Theloopthereforecanbeexecuted0-ntimesaccordingtotheconditionvalue.

Nowthebooleanexpressionevaluationasdescribedaboveislimitedtoverybasicoperationsuchaslowerthan,greaterthanandsoon.WealsocanuseHamcrestmatchersinconditionsthatarewaymorepowerfulthanthat.

XMLDSL

<testcasename="iterateTest"><actions><iterateindex="i"condition="@assertThat(lessThan(5))@"><echo><message>indexis:$i</message></echo></iterate></actions></testcase>

JavaDSLdesignerandrunner

@CitrusTestpublicvoiditerateTest()iterate().condition(lessThan(5)).index("i")).actions(echo("indexis:$i"));

IntheexampleaboveweuseHamcrestmatchersascondition.YoucancombineHamcrestmatchersandcreateverypowerfulconditionevaluationshere.

CitrusReferenceGuide

213Iterate

Page 214: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

CitrusReferenceGuide

214Iterate

Page 215: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Repeatuntiltrue

Quitesimilartothepreviouslydescribediteratecontainerthisrepeatingcontainerwillexecuteitsactionsinaloopaccordingtoanendingcondition.TheconditiondescribesaBooleanexpressionusingtheoperatorsasdescribedinthepreviouschapter.

NoteTheloopcontinuesitsworkuntiltheprovidedconditionevaluatestotrue.Itisveryimportanttonoticethattherepeatloopwillexecutetheactionsbeforeevaluatingthecondition.Thismeanstheactionsgetexecuted1-ntimes.

XMLDSL

<testcasename="iterateTest"><actions><repeat-until-trueindex="i"condition="(i=3)or(i=5)"><echo><message>indexis:$i</message></echo></repeat-until-true></actions></testcase>

JavaDSLdesignerandrunner

@CitrusTestpublicvoidrepeatTest()repeat().until("(igt5)or(i=3)").index("i")).actions(echo("indexis:$i"));

Asyoucanseetherepeatcontainerisonlyexecutedwhentheiteratingconditionexpressionevaluatestofalse.Bythetimetheconditionistrueexecutionisdiscontinued.Youcanusebasiclogicaloperatorssuchasand,orandsoon.

AmorepowerfulwayisgivenbyHamcrestmatchersthataredirectlysupportedinconditionexpressions.

XMLDSL

<testcasename="iterateTest"><actions>

CitrusReferenceGuide

215Repeat

Page 216: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<repeat-until-trueindex="i"condition="@assertThat(anyOf(is(3),is(5))@"><echo><message>indexis:$i</message></echo></repeat-until-true></actions></testcase>

JavaDSLdesignerandrunner

@CitrusTestpublicvoidrepeatTest()repeat().until(anyOf(is(3),is(5)).index("i")).actions(echo("indexis:$i"));

TheHamcrestmatcherusagesimplifiesthereadingalot.Anditempowersyoutocombinemorecomplexconditionexpressions.SoIpersonallypreferthissyntax.

CitrusReferenceGuide

216Repeat

Page 217: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Repeatonerroruntiltrue

Thenextloopingcontaineriscalledrepeat-on-error-until-true.Thiscontainerrepeatsagroupofactionsincaseoneembeddedactionfailedwitherror.Incaseofanerrorinsidethecontainertheloopwilltrytoexecuteallembeddedactionsagaininordertoseekforoverallsuccess.Theexecutioncontinuesuntilallembeddedactionswereprocessedsuccessfullyortheendingconditionevaluatestotrueandtheerror-loopwillleadtofinalfailure.

XMLDSL

<testcasename="iterateTest"><actions><repeat-onerror-until-trueindex="i"condition="i=5"><echo><message>indexis:$i</message></echo><fail/></repeat-onerror-until-true></actions></testcase>

JavaDSLdesigner

@CitrusTestpublicvoidrepeatOnErrorTest()repeatOnError(echo("indexis:$i"),fail("Forcelooptofail!")).until("i=5").index("i");

JavaDSLrunner

@CitrusTestpublicvoidrepeatOnErrorTest()repeatOnError().until("i=5").index("i")).actions(echo("indexis:$i"),fail("Forcelooptofail!"));

CitrusReferenceGuide

217RepeatOnError

Page 218: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Inthecodeexampletheerror-loopcontinuesfourtimesastheactiondefinitelyfailsthetest.DuringthefifthiterationThecondition"i=5"evaluatestotrueandtheloopbreaksitsprocessingleadingtoafinalfailureasthetestactionswerenotsuccessful.

NoteTheoverallsuccessofthetestcasedependsontheerrorsituationinsidetherepeat-onerror-until-truecontainer.Incasetheloopbreaksbecauseoffailingactionsandtheloopwilldiscontinueitsworkthewholetestcaseisfailingtoo.Theerrorloopprocessingissuccessfulincaseallembeddedactionswerenotraisinganyerrorsduringaniteration.

Therepeat-on-errorcontaineralsooffersanautomaticsleepmechanism.Thisauto-sleeppropertywillforcethecontainertowaitagivenamountoftimebeforeexecutingthenextiteration.Weusedthismechanismalotwhenvalidatingdatabaseentries.Let'ssaywewanttochecktheexistenceofanorderentryinthedatabase.Unfortunatelythesystemundertestisnotverywellperformingandmayneedsometimetostoretheneworder.Thisamountoftimeisnotpredictable,especiallywhendealingwithdifferenthardwareonourtestenvironments(localtestingvs.servertesting).Followingfromthatourtestcasemayfailunpredictableonlybecauseofruntimeconditions.

Wecanavoidunstabletestcasesthatarebasedontheseruntimeconditionswiththeauto-sleepfunctionality.

XMLDSL

<repeat-onerror-until-trueauto-sleep="1000"condition="i=5"index="i"><echo><sqldatasource="testDataSource"><statement>SELECTCOUNT(1)ASCNT_ORDERSFROMORDERSWHERECUSTOMER_ID='$customerId'</statement><validatecolumn="CNT_ORDERS"value="1"/></sql></echo></repeat-onerror-until-true>

JavaDSLdesignerandrunner

@CitrusTestpublicvoidrepeatOnErrorTest()repeatOnError().until("i=5").index("i").autoSleep(1000)).actions(query(action->action.dataSource(testDataSource)

CitrusReferenceGuide

218RepeatOnError

Page 219: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

.statement("SELECTCOUNT(1)ASCNT_ORDERSFROMORDERSWHERECUSTOMER_ID='$customerId'".validate("CNT_ORDERS","1")));

Wesurroundedthedatabasecheckwitharepeat-onerrorcontainerhavingtheauto-sleeppropertysetto1000milliseconds.Therepeatcontainerwilltrytocheckthedatabaseuptofivetimeswithanautomaticsleepof1secondbeforeeveryiteration.Thisgivesthesystemundertestuptofivesecondstimetostorethenewentrytothedatabase.Thetestcaseisverystableandjustfitstothehardwareenvironment.Onslowtestenvironmentsthetestmayneedseveraliterationstosuccessfullyreadthedatabaseentry.Onveryfastenvironmentsthetestmaysucceedrightonthefirsttry.

ImportantWechangedautosleeptimefromsecondstomillisecondswithCitrus2.0release.SoifyouarecomingfrompreviousCitrusversionsbesuretonowusepropermillisecondvalues.

Sofastenvironmentsarenotsloweddownbystaticsleepoperationsandslowerenvironmentsarestillabletoexecutethistestcasewithhighstability.

CitrusReferenceGuide

219RepeatOnError

Page 220: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Timer

Timersareveryusefulcontainerswhenyouwishtoexecuteacollectionoftestactionsseveraltimesatregularintervals.Thetimercomponentgeneratesaneventwhichinturntriggerstheexecutionofthenestedtestactionsassociatedwithtimer.ThiscanbeusefulinanumberoftestscenariosforexamplewhenCitrusneedstosimulateaheartbeatorifyouaredebuggingatestandyouwisttoquerythecontentsofthedatabase,tomentionjustafew.Thefollowingcodesampleshoulddemonstratethepowerandflexibilityoftimers:

XMLDSL

<testcasename="timerTest"><actions><timerid="forkedTimer"interval="100"fork="true"><echo><message>I'mgoingtoruninthebackgroundandletsomeothertestactionsrun(nestedactionrun$forkedTimer-indextimes)</echo><sleepmilliseconds="50"/></timer>

<timerrepeatCount="3"interval="100"delay="50"><sleepmilliseconds="50"/><echo><message>I'mgoingtorepeatthismessage3timesbeforethenexttestactionsareexecuted</echo></timer>

<echo><message>Testalmostcomplete.Makesurealltimersrunninginthebackgroundarestopped</echo></actions><finally><stop-timertimerId="forkedTimer"/></finally></testcase>

JavaDSLdesignerandrunner

@CitrusTestpublicvoidtimerTest()

timer().timerId("forkedTimer")

CitrusReferenceGuide

220Timer

Page 221: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

.interval(100L).fork(true).actions(echo("I'mgoingtoruninthebackgroundandletsomeothertestactionsrun(nestedactionrun$forkedTimer-indextimes)"sleep(50L));

timer().repeatCount(3).interval(100L).delay(50L).actions(sleep(50L),echo("I'mgoingtorepeatthismessage3timesbeforethenexttestactionsareexecuted");

echo("Testalmostcomplete.Makesurealltimersrunninginthebackgroundarestopped");

doFinally().actions(stopTimer("forkedTimer"));

Intheaboveexamplethefirsttimer(timerId=forkedTimer)isstartedinthebackground.Bydefaulttimersareruninthecurrentthreadofexecutionbuttostartitinthebackgroundjustuse"fork=true".Every100millisecondsthistimeremitsaneventwhichwillresultinthenestedactionsbeingexecuted.Thenested'echo'actionoutputsthenumberoftimesthistimerhasalreadybeenexecuted.Itdoesthiswiththehelpofan'index'variable,inthisexample$forkedTimer-index,whichisnamedaccordingtothetimeridwiththesuffix'-index'.Nolimitissetonthenumberoftimesthistimershouldrunsoitwillkeeponrunninguntileitheranestedtestactionfailsoritisinstructedtostop(moreonthisbelow).

Thesecondtimerisconfiguredtorun3timeswithadelayof100millisecondsbetweeneachiteration.Usingtheattribute'delay'wecangetthetimerpausefor50millisecondsbeforerunningthenestedactionsforthefirsttime.Thetimerisconfiguredtoruninthecurrentthreadofexecutionsothelasttestaction,the'echo',hastowaitforthistimertocompletebeforeitisexecuted.

Sohowdowetelltheforkedtimertostoprunning?Ifweforgettodothisthetimerwilljustexecuteindefinitely.Tohelpusoutherewecanusethe'stop-timer'action.Byaddingthistothefinallyblockweensurethatthetimerwillbestopped,evenifsome

CitrusReferenceGuide

221Timer

Page 222: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

nestedtestactionfails.Wecouldhaveeasilyaddeditasanestedtestaction,totheforkedTimerforexample,butifsomeothertestactionfailedbeforethestop-timerwascalled,thetimerwouldneverstop.

NoteYoucanalsoconfiguretimerstoruninthebackgroundusingthe'parallel'container,ratherthansettingtheattribute'fork'totrue.Usingparallelallowsmorefine-grainedcontrolofthetestandhastheaddedadvantagethatallerrorsgeneratedfromanestertimeractionarevisibletothetestexecuter.Ifanerroroccurswithinthetimerthentheteststatusissettofailed.Usingfork=trueanerrorcausesthetimertostopexecuting,buttheteststatusisnotinfluencedbythiserror.

CitrusReferenceGuide

222Timer

Page 223: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Customcontainers

IncaseyouhaveacustomactioncontainerimplementationyoumightalsowanttouseitinJavaDSL.TheactioncontainersarehandledwithspecialcareintheJavaDSLbecausetheyhavenestedactions.SowhenyoucallatestactioncontainerintheJavaDSLyoualwayshavesomethinglikethis:

JavaDSLdesignerandrunner

@CitrusTestpublicvoidcontainerTest()echo("Thisechoisoutsideoftheactioncontainer");

sequential().actions(echo("Inside"),echo("Insideoncemore"),echo("Andagain:Inside!"));

echo("Thisechoisoutsideoftheactioncontainer");

NowthethreenestedactionsareaddedtotheactionsequentialcontainerratherthantothetestcaseitselfalthoughweareusingthesameactionJavaDSLmethodsasoutsidethecontainer.ThismechanismisonlyworkingbecauseCitrusishandlingtestactioncontainerswithspecialcare.

Acustomtestactioncontainerimplementationcouldlooklikethis:

publicclassReverseActionContainerextendsAbstractActionContainer@OverridepublicvoiddoExecute(TestContextcontext)for(inti=getActions().size();i>0;i--)getActions().get(i-1).execute(context);

Thecontainerlogicisverysimple:Thecontainerexecutesthenestedactionsinreverseorder.AsalreadymentionedCitrusneedstotakespecialcareonallactioncontainerswhenexecutingaJavaDSLtest.Thisiswhyyoushouldnotexecuteacustomtestcontainerimplementationonyourown.

CitrusReferenceGuide

223Custom

Page 224: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

@CitrusTestpublicvoidcontainerTest()ReverseActionContainerreverseContainer=newReverseActionContainer();reverseContainer.addTestAction(newEchoAction().setMessage("Foo"));reverseContainer.addTestAction(newEchoAction().setMessage("Bar"));run(reverseContainer);

TheabovecustomcontainerexecutionisgoingtofailwithinternalerrorastheCitrusJavaDSLwasnotabletorecognisetheactioncontainerasitshouldbe.AlsotheEchoActioninstancecreationisnotverycomfortable.InsteadyoucanuseaspecialcontainerJavaDSLsyntaxalsowithyourcustomcontainerimplementation:

@CitrusTestpublicvoidcontainerTest()container(newReverseActionContainer()).actions(echo("Foo"),echo("Bar"));

Thecustomcontainerimplementationnowworksfinewiththeautomaticallynestedechoactions.AndweareabletousetheusualJavaDSLsyntacticsugarfortestactionslikeecho.

Inanextstepweaddacustomsuperclassforallourtestclasseswhichprovidesahelpermethodforthecustomcontainerimplementationinordertohaveaevenmorecomfortablesyntax.

JavaDSLdesignerandrunner

publicclassCustomCitrusBaseTestextendsTestNGCitrusTestDesigner

publicAbstractTestContainerBuilder<ReverseActionContainer>reverse()returncontainer(newReverseActionContainer());

Nowallsubclassescanusethenewreversemethodforcallingthecustomcontainerimplementation.

@CitrusTestpublicvoidcontainerTest()

CitrusReferenceGuide

224Custom

Page 225: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

reverse().actions(echo("Foo"),echo("Bar"));

Nice!ThisishowweshouldintegratecustomizedtestactioncontainerstotheCitrusJavaDSL.

CitrusReferenceGuide

225Custom

Page 226: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

FinallysectionThischapterdealswithaspecialsectioninsidethetestcasethatisexecutedevenincaseerrorsdidoccurduringthetest.LetssayyouhavestartedaJettywebserverinstanceatthebeginningofthetestcaseandyouneedtoshutdowntheserverwhenthetesthasfinisheditswork.Orasasecondexampleimaginethatyouhavepreparedsomedatainsidethedatabaseatthebeginningofyourtestandyouwanttomakesurethatthedataiscleanedupattheendofthetestcase.

Inbothsituationswemightrunintosomeproblemswhenthetestfailed.Wefacetheproblemthatthewholetestcasewillterminateimmediatelyincaseoferrors.Cleanuptasksattheendofthetestactionchainmaynotbeexecutedcorrectly.

Dirtystatesinsidethedatabaseorstillrunningserverinstancesthenmightcauseproblemsforfollowingtestcases.Toavoidthisproblemsyoushouldusethefinallyblockofthetestcase.Thesectioncontainsactionsthatareexecutedevenincasethetestfails.Usingthisstrategythedatabasecleaningtasksmentionedbeforewillfindexecutionineverycase(successorfailure).

Thefollowingexampleshowshowtousethefinallysectionattheendofatest:

XMLDSL

<testcasename="finallyTest"><variables><variablename="orderId"value="citrus:randomNumber(5)"/><variablename="date"value="citrus:currentDate('dd.MM.yyyy')"/></variables><actions><sqldatasource="testDataSource"><statement>INSERTINTOORDERSVALUES($orderId,1,1,'$date')</statement></sql>

<echo><message>ORDERcreationtime:$date</message></echo></actions><finally><sqldatasource="testDataSource"><statement>

CitrusReferenceGuide

226Finally

Page 227: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

DELETEFROMORDERSWHEREORDER_ID='$orderId'</statement></sql></finally></testcase>

IntheexamplethefirstactioncreatesanentryinthedatabaseusinganINSERTstatement.Tobesurethattheentryinthedatabaseisdeletedafterthetest,thefinallysectioncontainstherespectiveDELETEstatementthatisalwaysexecutedregardlessthetestcasestate(successfulorfailed).

OfcourseyoucanalsousethefinallyblockintheJavatestcaseDSL.Findfollowingexampletoseehowitworks:

JavaDSLdesigner

@CitrusTestpublicvoidfinallySectionTest()variable("orderId","citrus:randomNumber(5)");variable("date","citrus:currentDate('dd.MM.yyyy')");

sql(dataSource).statement("INSERTINTOORDERSVALUES($orderId,1,1,'$date')");

echo("ORDERcreationtime:citrus:currentDate('dd.MM.yyyy')");

doFinally(sql(dataSource).statement("DELETEFROMORDERSWHEREORDER_ID='$orderId'"));

JavaDSLrunner

@CitrusTestpublicvoidfinallySectionTest()variable("orderId","citrus:randomNumber(5)");variable("date","citrus:currentDate('dd.MM.yyyy')");

sql(action->action.dataSource(dataSource).statement("INSERTINTOORDERSVALUES($orderId,1,1,'$date')"));

echo("ORDERcreationtime:citrus:currentDate('dd.MM.yyyy')");

doFinally().actions(sql(action->action.dataSource(dataSource).statement("DELETEFROMORDERSWHEREORDER_ID='$orderId'");

CitrusReferenceGuide

227Finally

Page 228: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

NoteJavadevelopersmightaskwhynotusetry-finallyJavablockinstead?Theanswerissimpleyetveryimportanttounderstand.The@CitrusTestannotatedmethodiscalledatdesigntimeofthetestcase.Themethodbuildsthetestcaseafterwardsthetestisexecutedatruntime.Thismeansthatatry-finallyblockwithinthe@CitrusTestannotatedmethodwillneverperformduringthetestrunbutatdesigntimebeforethetestgetsexecuted.ThisiswhywehavetoaddthefinallysectionaspartofthetestcasewithdoFinally().

CitrusReferenceGuide

228Finally

Page 229: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

JMSsupportCitrusprovidessupportforsendingandreceivingJMSmessages.Wehavetoseparatebetweensynchronousandasynchronouscommunication.SointhischapterweexplainhowtosetupJMSmessageendpointsforsynchronousandasynchronousoutboundandinboundcommunication

NoteTheJMScomponentsinCitrusarekeptinaseparateMavenmodule.IfnotalreadydonesoyouhavetoincludethemoduleasMavendependencytoyourproject

<dependency><groupId>com.consol.citrus</groupId><artifactId>citrus-jms</artifactId><version>2.7.1</version></dependency>

Citrusprovidesa"citrus-jms"configurationnamespaceandschemadefinitionforJMSrelatedcomponentsandfeatures.IncludethisnamespaceintoyourSpringconfigurationinordertousetheCitrusJMSconfigurationelements.ThenamespaceURIandschemalocationareaddedtotheSpringconfigurationXMLfileasfollows.

<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:citrus-jms="http://www.citrusframework.org/schema/jms/config"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/jms/confighttp://www.citrusframework.org/schema/jms/config/citrus-jms-config.xsd">

[...]

</beans>

AfterthatyouareabletousecustomizedCitrusXMLelementsinordertodefinetheSpringbeans.

JMSendpoints

CitrusReferenceGuide

229Jms

Page 230: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

BydefaultCitrusJMSendpointsareasynchronous.Soletusfirstofalldealwithasynchronousmessagingwhichmeansthatwewillnotwaitforanyresponsemessageaftersendingorreceivingamessage.

ThetestcaseitselfshouldnotknowaboutJMStransportdetailslikequeuenamesorconnectioncredentials.ThisinformationisstoredintheendpointcomponentconfigurationthatlivesinthebasicSpringconfigurationfileinCitrus.SoletushavealookatasimpleJMSmessageendpointconfigurationinCitrus.

<citrus-jms:endpointid="helloServiceQueueEndpoint"destination-name="Citrus.HelloService.Request.Queue"timeout="10000"/>

TheendpointcomponentreceivesanuniqueidandaJMSdestinationname.Thiscanbeaqueueortopicdestination.WewilldealwithJMStopicslateron.FornowthetimeoutsettingcompletesourfirstJMSendpointcomponentdefinition.

TheendpointneedsaJMSconnectionfactoryforconnectingtoaJMSmessagebroker.TheconnectionfactoryisalsoaddedasSpringbeantotheCitrusSpringapplicationcontext.

<beanid="connectionFactory"class="org.apache.activemq.ActiveMQConnectionFactory"><propertyname="brokerURL"value="tcp://localhost:61616"/></bean>

TheJMSconnectionfactoryreceivestheJMSmessagebrokerURLandisabletoholdmanyotherconnectionspecificoptions.InthisexampleweusetheApacheActiveMQconnectionfactoryimplementationaswewanttousetheActiveMQmessagebroker.CitrusworksbydefaultwithabeanidconnectionFactory.AllCitrusJMScomponentwillautomaticallyrecognizethisconnectionfactory.

TipSpringmakesitveryeasytoconnecttootherJMSbrokerimplementationstoo(e.g.ApacheActiveMQ,TIBCOEnterpriseMessagingService,IBMWebsphereMQ).JustaddtherequiredconnectionfactoryimplementationasconnectionFactorybean.

NoteAlloftheCitrusJMSendpointcomponentswillautomaticallylookforabeannamedconnectionFactorybydefault.Youcanusetheconnection-factoryendpointattributeinordertouseanotherconnectionfactoryinstancewithdifferentbeannames.

<citrus-jms:endpointid="helloServiceQueueEndpoint"destination-name="Citrus.HelloService.Request.Queue"

CitrusReferenceGuide

230Jms

Page 231: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

connection-factory="myConnectionFacotry"/>

AsanalternativetothatyoumaywanttouseaspecialSpringjmstemplateimplementationascustombeaninyourendpoint.

<citrus-jms:endpointid="helloServiceQueueEndpoint"destination-name="Citrus.HelloService.Request.Queue"jms-template="myJmsTemplate"/>

Theendpointisnowreadytobeusedinsideatestcase.Insideatestcaseyoucansendorreceivemessagesusingthisendpoint.ThetestactionscanreferencetheJMSendpointusingitsidentifier.WhensendingamessagethemessageendpointcreatesaJMSmessageproducerandwillsimplypublishthemessagetothedefinedJMSdestination.Asthecommunicationisasynchronousbydefaultproducerdoesnotwaitforasynchronousresponse.

WhenreceivingamessageswiththisendpointtheendpointcreatesaJMSconsumerontheJMSdestination.Theendpointthenactsasamessagedrivenlistener.Thismeansthatthemessageconsumerconnectstothegivendestinationandwaitsformessagestoarrive.

NoteBesidesthedestination-nameattributeyoucanalsoprovideareferencetoadestinationimplementation.

<citrus-jms:endpointid="helloServiceQueueEndpoint"destination="helloServiceQueue"/>

<amq:queueid="helloServiceQueue"physicalName="Citrus.HelloService.Request.Queue"/>

ThedestinationattributereferencestoaJMSdestinationobjectintheSpringapplicationcontext.IntheexampleaboveweusedtheActiveMQqueuedestinationcomponent.ThedestinationreferencecanalsorefertoaJNDIlookupforinstance.

JMSsynchronousendpoints

WhenusingsynchronousmessageendpointsCitruswillmanageareplydestinationforreceivingasynchronousresponsemessageonthereplydestination.Thefollowingfigureillustratesthatwenowhavetwodestinationsinourcommunicationscenario.

CitrusReferenceGuide

231Jms

Page 232: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Thesynchronousmessageendpointcomponentissimilartotheasynchronousbrotherthatwehavediscussedbefore.Theonlydifferenceisthattheendpointwillautomaticallymanageareplydestinationbehindthescenes.BydefaultCitrususestemporaryreplydestinationsthatgetautomaticallydeletedafterthecommunicationhandshakeisdone.AgainweneedtouseaJMSconnectionfactoryintheSpringXMLconfigurationasthecomponentneedtoconnecttoaJMSmessagebroker.

<citrus-jms:sync-endpointid="helloServiceSyncEndpoint"destination-name="Citrus.HelloService.InOut.Queue"timeout="10000"/>

Thesynchronouscomponentdefinesatargetdestinationwhichagainiseitheraqueueortopicdestination.Ifnothingelseisdefinedtheendpointwillcreatetemporaryreplydestinationsonitsown.Whentheendpointhassentamessageitwaitssynchronouslyfortheresponsemessagetoarriveonthereplydestination.Youcanreceivethisreplymessageinyourtestcasebyreferencingthissameendoointinareceivetestaction.Incasenoreplymessagearrivesintimeamessagetimeouterrorisraisedrespectively.

Seethefollowingexampletestcasewhichreferencesthesynchronousmessageendpointinitssendandreceivetestactioninordertosendoutamessageandwaitforthesynchronousresponse.

<testcasename="synchronousMessagingTest"><actions><sendendpoint="helloServiceSyncEndpoint"><message><data>[...]</data></message></send>

<receiveendpoint="helloServiceSyncEndpoint"><message><data>[...]</data></message>

CitrusReferenceGuide

232Jms

Page 233: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</receive></actions></testcase>

Weinitiatedthesynchronouscommunicationbysendingamessageonthesynchronousendpoint.Thesecondstepthenreceivesthesynchronousmessageonthetemporaryreplydestinationthatwasautomaticallycreatedforus.

Ifyouratherwanttodefineastaticreplydestinationyoucandoso,too.Thestaticreplydestinationisnotdeletedaftercommunicationhandshake.Youmayneedtoworkwithmessageselectorstheninordertopicktherightresponsemessagethatbelongstoaspecificcommunicationhandshake.Youcandefineastaticreplydestinationonthesynchronousendpointcomponentasfollows.

<citrus-jms:sync-endpointid="helloServiceSyncEndpoint"destination-name="Citrus.HelloService.InOut.Queue"reply-destination-name="Citrus.HelloService.Reply.Queue"timeout="10000"/>

Insteadofusingthereply-destination-namefeelfreetousethedestinationreferencewithreply-destinationattribute.AgainyoucanuseaJNDIlookupthentoreferenceadestinationobject.

ImportantBeawareofpermissionsthataremandatoryforcreatingtemporarydestinations.CitrustriestocreatetemporaryqueuesontheJMSmessagebroker.FollowingfromthattheCitrusJMSuserhastohavethepermissiontodoso.Besurethattheuserhasthesufficientrightswhenusingtemporaryreplydestinations.

Uptonowwehavesentamessageandwaitedforasynchronousresponseinthenextstep.Nowitisalsopossibletoswitchthedirectionsofsendandreceiveactions.ThenwehavethesituationwhereCitrusreceivesaJMSmessagefirstandthenCitrusisinchargeofprovidingapropersynchronousresponsemessagetotheinitialsender.

InthisscenariotheforeignmessageproducerhasstoredadynamicJMSreplyqueuedestinationtotheJMSheader.SoCitrushastosendthereplymessagetothisspecificreplydestination,whichisdynamicofcourse.Fortunatelytheheavyliftisdonewiththe

CitrusReferenceGuide

233Jms

Page 234: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

JMSmessageendpointandwedonothavetochangeanythinginourconfiguration.Againwejustdefineasynchronousmessageendpointintheapplicationcontext.

<citrus-jms:sync-endpointid="helloServiceSyncEndpoint"destination-name="Citrus.HelloService.InOut.Queue"timeout="10000"/>

Nowtheonlythingthatchangeshereisthatwefirstreceiveamessageinourtestcaseonthisendpoint.Thesecondstepisasendmessageactionthatreferencesthissameendpointandwearedone.Citrusautomaticallymanagesthereplydestinationsforus.

<testcasename="synchronousMessagingTest"><actions><receiveendpoint="helloServiceSyncEndpoint"><message><data>[...]</data></message></receive>

<sendendpoint="helloServiceSyncEndpoint"><message><data>[...]</data></message></send></actions></testcase>

JMStopics

UptonowwehaveusedJMSqueuedestinationsonourendpoints.CitrusisalsoabletoconnecttoJMStopicdestinations.IncontrarytoJMSqueueswhichrepresentsthepoint-to-pointcommunicationJMStopicsusepublish-subscribemechanisminordertospreadmessagesoverJMS.AJMStopicproducerpublishesmessagestothetopic,whilethetopicacceptsmultiplemessagesubscriptionsanddeliversthemessagetoallsubscribers.

TheCitrusJMSendpointsoffertheattribute'pub-sub-domain'.OncethisattributeissettotrueCitruswilluseJMStopicsinsteadofqueuedestinations.Seethefollowingexamplewherethepublish-subscribeattributeissettotrueinJMSmessageendpoint

CitrusReferenceGuide

234Jms

Page 235: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

components.

<citrus-jms:endpointid="helloServiceQueueEndpoint"destination="helloServiceQueue"pub-sub-domain="true"/>

WhenusingJMStopicsyouwillbeabletosubscribeseveraltestactionstothetopicdestinationandreceiveamessagemultipletimesasallsubscriberswillreceivethemessage.

ImportantItisveryimportanttokeepinmindthatCitrusdoesnotdealwithdurablesubscribers.Thismeansthatmessagesthatweresentinadvancetothemessagesubscriptionarenotdeliveredtothemessageendpoint.SoracingconditionsmaycauseproblemswhenusingJMStopicendpointsinCitrus.BesuretoletCitrussubscribetothetopicbeforemessagesaresenttoit.Otherwiseyoumayloosesomemessagesthatweresentinadvancetothesubscription.

JMSmessageheaders

TheJMSspecificationdefinesasetofspecialmessageheaderentriesthatcangointoyourJMSmessage.TheseJMSheadersarestoreddifferentlyinaJMSmessageheaderthanothercustomheaderentriesdo.Thereforethesespecialheadervaluesshouldbesetinaspecialsyntaxthatwediscussinthenextparagraphs.

<header><elementname="citrus_jms_correlationId"value="$correlationId"/><elementname="citrus_jms_messageId"value="$messageId"/><elementname="citrus_jms_redelivered"value="$redelivered"/><elementname="citrus_jms_timestamp"value="$timestamp"/></header>

AsyouseeallJMSspecificmessageheadersusethecitrusjmsprefix.ThisprefixcomesfromSpringIntegrationmessageheadermappersthattakecareofsettingthoseheadersintheJMSmessageheaderproperly.

TypingofmessageheaderentriesmayalsobeofinterestinordertomeettheJMSstandardsoftypedmessageheaders.ForinstancethefollowingmessageheaderisoftypedoubleandisthereforetransferredviaJMSasadoublevalue.

<header><elementname="amount"value="19.75"type="double"/></header>

CitrusReferenceGuide

235Jms

Page 236: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

SOAPoverJMS

WhensendingSOAPmessagesyouhavetodealwithproperenvelope,bodyandheaderconstruction.InCitrusyoucanaddaspecialmessageconverterthatperformstheheavyliftforyou.JustaddthemessageconvertertotheJMSendpointasshowninthenextprogramlisting:

<citrus-jms:endpointid="helloServiceSoapJmsEndpoint"destination-name="Citrus.HelloService.Request.Queue"message-converter="soapJmsMessageConverter"/>

<beanid="soapJmsMessageConverter"class="com.consol.citrus.jms.message.SoapJmsMessageConverter"

WiththismessageconverteryoucanskiptheSOAPenvelopecompletelyinyourtestcase.Youjustdealwiththemessagebodypayloadandtheheaderentries.Therestisdonebythemessageconverter.SoyougetproperSOAPmessagesontheproducerandconsumerside.

CitrusReferenceGuide

236Jms

Page 237: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

HTTPRESTsupportRESTAPIshavegainedmoreandmoresignificanceregardingclient-serverinterfaces.TheRESTclientisnothingbutaHTTPclientsendingHTTPrequestsusuallyinJSONdataformattoaHTTPserver.AsHTTPisasynchronousprotocolbynaturetheclientreceivestheserverresponsesynchronously.CitrusisabletoconnectwithHTTPservicesandtestRESTAPIsonbothclientandserversidewithapowerfulJSONmessagedatasupport.InthenextsectionsyouwilllearnhowtoinvokeHTTPservicesasaclientandhowtohandleRESTHTTPrequestsinatestcase.WedealwithsettingupaHTTPserverinordertoacceptclientrequestsandprovideproperHTTPresponseswithGET,PUT,DELETEorPOSTrequestmethod.

NoteThehttpcomponentsinCitrusarekeptinaseparateMavenmodule.SoyoushouldaddthemoduleasMavendependencytoyourprojectaccordingly.

<dependency><groupId>com.consol.citrus</groupId><artifactId>citrus-http</artifactId><version>2.7.1</version></dependency>

AsCitrusprovidesacustomizedHTTPconfigurationschemafortheSpringapplicationcontextconfigurationfileswehavetoaddnametothetoplevelbeanselement.Simplyincludethehttp-confignamespaceintheconfigurationXMLfilesasfollows.

<beansxmlns="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-http="http://www.citrusframework.org/schema/http/config"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/confighttp://www.citrusframework.org/schema/config/citrus-config.xsdhttp://www.citrusframework.org/schema/http/confighttp://www.citrusframework.org/schema/http/config/citrus-http-config.xsd">

[...]

</beans>

CitrusReferenceGuide

237Http

Page 238: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

NowwearereadytousethecustomizedCitrusHTTPconfigurationelementswiththecitrus-httpnamespaceprefix.

HTTPRESTclient

OntheclientsidewehaveasimpleHTTPmessageclientcomponentconnectingtotheserver.Therequest-urlattributedefinestheHTTPserverendpointURLtoconnectto.Asusualyoucanreferencethisclientinyourtestcaseinordertosendandreceivemessages.Citrusasclientwaitsfortheresponsemessagefromserver.Afterthattheresponsemessagegoesthroughthevalidationprocessasusual.LetusseehowaCitrusHTTPclientcomponentlookslike:

<citrus-http:clientid="helloHttpClient"request-url="http://localhost:8080/hello"request-method="GET"content-type="application/xml"timeout="60000"/>

Therequest-methoddefinestheHTTPmethodtouse.Inadditiontothatwecanspecifythecontent-typeoftherequestweareabouttosend.TheclientbuildstheHTTPrequestandsendsittotheHTTPserver.WhiletheclientiswaitingforthesynchronousHTTPresponsetoarriveweareabletopollseveraltimesfortheresponsemessageinourtestcase.Asusualaoucanusethesameclientendpointinyourtestcasetosendandreceivemessagessynchronously.Incasethereplymessagecomesintoolateaccordingtothetimeoutsettingsarespectivetimeouterrorisraised.

HttpdefinesseveralrequestmethodsthataclientcanusetoaccessHttpserverresources.IntheexampleclientaboveweareusingGETasdefaultrequestmethod.OfcourseyoucanoverwritethissettinginatestcaseactionbysettingtheHTTPrequestmethodinsidethesendingtestaction.TheHttpclientcomponentcanbeusedasnormalendpointinasendingtestaction.Usesomethinglikethisinyourtest:

XMLDSL

<sendendpoint="helloHttpClient"><message><payload><TestMessage><Text>HelloHttpServer</Text></TestMessage></payload></message>

CitrusReferenceGuide

238Http

Page 239: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<header><elementname="citrus_http_method"value="POST"/></header></send>

TipCitrususestheSpringRESTtemplatemechanismforsendingoutHTTPrequests.ThismeansyouhavegreatcustomizingopportunitieswithaspecialRESTtemplateconfiguration.YoucanthinkofbasicHTTPauthentication,readtimeoutsandspecialmessagefactoryimplementations.JustusethecustomRESTtemplateattributeinclientconfigurationlikethis:

<citrus-http:clientid="helloHttpClient"request-url="http://localhost:8080/hello"request-method="GET"content-type="text/plain"rest-template="customizedRestTemplate"/>

<!--Customizedresttemplate--><beanname="customizedRestTemplate"class="org.springframework.web.client.RestTemplate"><propertyname="messageConverters"><util:listid="converter"><beanclass="org.springframework.http.converter.StringHttpMessageConverter"><propertyname="supportedMediaTypes"><util:listid="types"><value>text/plain</value></util:list></property></bean></util:list></property><propertyname="errorHandler"><!--Customerrorhandler--></property><propertyname="requestFactory"><beanclass="org.springframework.http.client.HttpComponentsClientHttpRequestFactory"><propertyname="readTimeout"value="9000"/></bean></property></bean>

UptonowwehaveusedanormalsendtestactiontosendHttprequestsasaclient.ThisiscompletelyvalidstrategyastheCitrusHttpclientisanormalendpoint.ButwemightwanttosetsomemoreHttpRESTspecificpropertiesandsettings.InordertosimplifytheHttpusageinatestcasewecanuseaspecialtestactionimplementation.TheCitrusHttpspecificactionsarelocatedinaseparateXMLnamespace.SowenneedtoaddthisnamespacetoourtestcaseXMLfirst.

CitrusReferenceGuide

239Http

Page 240: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:http="http://www.citrusframework.org/schema/http/testcase"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/http/testcasehttp://www.citrusframework.org/schema/http/testcase/citrus-http-testcase.xsd">

[...]

</beans>

ThetestcaseisnowreadytousethespecificHttptestactionsbyusingtheprefixhttp:.

XMLDSL

<http:send-requestclient="httpClient"><http:POSTpath="/customer"><http:headerscontent-type="application/xml"accept="application/xml,*/*"><http:headername="X-CustomHeaderId"value="$custom_header_id"/></http:headers><http:body><http:data><![CDATA[<customer><id>citrus:randomNumber()</id><name>testuser</name></customer>]]></http:data></http:body></http:POST></http:send-request>

TheactionaboveusesseveralHttpspecificsettingssuchastherequestmethodPOSTaswellasthecontent-typeandacceptheaders.AsusualthesendactionneedsatargetHttpclientendpointcomponent.Wecanspecifyarequestpathattributethataddedasrelativepathtothebaseuriusedontheclient.

WhenusingaGETrequestwecanspecifysomerequesturiparameters.

XMLDSL

<http:send-requestclient="httpClient"><http:GETpath="/customer/$custom_header_id"><http:paramscontent-type="application/xml"accept="application/xml,*/*">

CitrusReferenceGuide

240Http

Page 241: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<http:paramname="type"value="active"/></http:params></http:GET></http:send-request>

ThesendactionaboveusesaGETrequestontheendpointurihttp://localhost:8080/customer/1234?type=active.

OfcoursewhensendingHttpclientrequestswearealsointerestedinreceivingHttpresponsemessages.WewanttovalidatethesuccessresponsewithHttpstatuscode.

XMLDSL

<http:receive-responseclient="httpClient"><http:headersstatus="200"reason-phrase="OK"version="HTTP/1.1"><http:headername="X-CustomHeaderId"value="$custom_header_id"/></http:headers><http:body><http:data><![CDATA[<customerResponse><success>true</success></customerResponse>]]></http:data></http:body></http:receive-response>

Thereceive-responsetestactionalsousesaclientcomponent.Wecanexpectresponsestatuscodeinformationsuchasstatusandreason-phrase.OfcourseCitruswillraiseavalidationexceptionincaseHttpstatuscodesmismatch.

UptonowwehaveusedXMLDSLtestcases.TheJavaDSLinCitrusalsoworkswithspecificHttptestactions.Seefollowingexampleandfindouthowthisworks:

XMLDSL

@CitrusTestpublicvoidhttpActionTest()http().client("httpClient").send().post("/customer").payload("<customer>"+"<id>citrus:randomNumber()</id>"+"<name>testuser</name>"+"</customer>").header("X-CustomHeaderId","$custom_header_id")

CitrusReferenceGuide

241Http

Page 242: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

.contentType("text/xml").accept("text/xml,*/*");

http().client("httpClient").receive().response(HttpStatus.OK).payload("<customerResponse>"+"<success>true</success>"+"</customerResponse>").header("X-CustomHeaderId","$custom_header_id").version("HTTP/1.1");

Thereisonemoresettingontheclienttobeawareof.BydefaulttheclientcomponentwilladdtheAccepthttpheaderandsetitsvaluetoalistofallsupportedencodingsonthehostoperatingsystem.Asthislistcangetverylongyoumaywanttonotsetthisdefaultacceptheader.ThesettingisdoneintheSpringRestTemplate:

<beanname="customizedRestTemplate"class="org.springframework.web.client.RestTemplate"><propertyname="messageConverters"><util:listid="converter"><beanclass="org.springframework.http.converter.StringHttpMessageConverter"><propertyname="writeAcceptCharset"value="false"/></bean></util:list></property></bean>

YouwouldhaveaddthiscustomRestTemplateconfigurationandsetittotheclientcomponentwithrest-templateproperty.ButfortunatelytheCitrusclientcomponentprovidesaseparatesettingdefault-accept-headerwhichisaBooleansetting.Bydefaultitissettotruesothedefaultacceptheaderisautomaticallyaddedtoallrequests.Ifyousetthisflagtofalsetheheaderisnotset:

<citrus-http:clientid="helloHttpClient"request-url="http://localhost:8080/hello"request-method="GET"content-type="text/plain"default-accept-header="false"/>

OfcourseyoucansettheAcceptheaderoneachsendoperationinordertotelltheserverwhatkindofcontenttypesaresupportedinresponsemessages.

CitrusReferenceGuide

242Http

Page 243: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

NowwecansendandreceivemessagesasHttpclientwithspecifictestactions.NowletsmoveontotheHttpserver.

HTTPclientinterceptors

Theclientcomponentisabletoaddcustominterceptorsthatparticipateintherequest/responseprocessing.Theinterceptorsneedtoimplementthecommoninterfaceorg.springframework.http.client.ClientHttpRequestInterceptor.

<citrus-http:clientid="helloHttpClient"request-url="http://localhost:8080/hello"request-method="GET"interceptors="clientInterceptors"/>

<util:listid="clientInterceptors"><beanclass="com.consol.citrus.http.interceptor.LoggingClientInterceptor"/></util:list>

ThesampleaboveaddstheCitrusloggingclientinterceptorthatlogsrequestsandresponsesexchangedwiththatclientcomponent.Youcanaddcustominterceptorimplementationshereinordertoparticipateintherequest/responsemessageprocessing.

HTTPRESTserver

TheHTTPclientwasquiteeasyandstraightforward.ReceivingHTTPmessagesisalittlebitmorecomplicatedbecauseCitrushastoprovideserverfunctionalitylisteningonalocalportforclientconnections.ThereforeCitrusoffersanembeddedHTTPserverwhichiscapableofhandlingincomingHTTPrequests.OnceaclientconnectionisacceptedtheHTTPservermustalsoprovideaproperHTTPresponsetotheclient.InthenextfewlinesyouwillseehowtosimulateserversideHTTPRESTservicewithCitrus.

<citrus-http:serverid="helloHttpServer"port="8080"auto-start="true"resource-base="src/it/resources"/>

CitrususesanembeddedJettyserverthatwillautomaticallystartwhentheSpringapplicationcontextisloaded(auto-start="true").Thebasicconnectorislisteningonport8080forrequests.Testcasescaninteractwiththisserverinstanceviamessage

CitrusReferenceGuide

243Http

Page 244: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

channelsbydefault.Theserverprovidesaninboundchannelthatholdsincomingrequestmessages.Thetestcasecanreceivethoserequestsfromthechannelwithanormalreceivetestaction.InasecondstepthetestcasecanprovideasynchronousresponsemessageasreplywhichwillbeautomaticallysentbacktotheHTTPclientasresponse.

Thefigureaboveshowsthebasicsetupwithinboundchannelandreplychannel.Youasatestershouldnotworryaboutthistomuch.Bydefaultyouasatesterjustusetheserverassynchronousendpointinyourtestcase.Thismeansthatyousimplyreceiveamessagefromtheserverandsendaresponseback.

<testcasename="httpServerTest"><actions><receiveendpoint="helloHttpServer"><message><data>[...]</data></message></receive>

<sendendpoint="helloHttpServer"><message><data>[...]</data></message></send></actions></testcase>

Asyoucanseewereferencetheserveridinbothreceiveandsendactions.TheCitrusserverinstancewillautomaticallysendtheresponsebacktothecallingHTTPclient.Inmostcasesthisisexactlywhatwewanttodo-sendbackaresponsemessagethatisspecifiedinsidethetest.TheHTTPservercomponentbydefaultusesachannelendpointadapterinordertoforwardallincomingrequeststoaninmemorymessagechannel.Thisisdonecompletelybehindthescenes.TheHttpservercomponentprovidessomemorecustomizationpossibilitieswhenitcomestoendpointadapter

CitrusReferenceGuide

244Http

Page 245: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

implementations.Thistopicisdiscussedinaseparatesectionendpoint-adapter.Uptonowwekeepitsimplebysynchronouslyreceivingandsendingmessagesinthetestcase.

TipThedefaultchannelendpointadapterautomaticallycreatesaninboundmessagechannelwhereincomingmessagesarestoredtointernally.Soifyouneedtocleanupaserverthathasalreadystoredsomeincomingmessagesyoucandothiseasilybypurgingtheinternalmessagechannel.ThemessagechannelfollowsanamingconventionserverName.inboundwhereserverNameistheSpringbeannameoftheCitrusserverendpointcomponent.Ifyoupurgethisinternalchannelinabeforetestnatureyouaresurethatobsoletemessagesonaserverinstancegetpurgedbeforeeachtestisexecuted.

Soletsgetbacktoourmissionofprovidingresponsemessagesasservertoconnectedclients.AsyoumightknowHttpRESTworkswithsomecharacteristicpropertieswhenitcomestosendandreceivemessages.ForinstanceaclientcansenddifferentrequestmethodsGET,POST,PUT,DELETE,HEADandsoon.TheCitrusservermayverifythismethodwhenreceivingclientrequests.ThereforewehaveintroducedspecialHttptestactionsforservercommunication.Havealookatasimpleexample:

<http:receive-requestserver="helloHttpServer"><http:POSTpath="/test"><http:headerscontent-type="application/xml"accept="application/xml,*/*"><http:headername="X-CustomHeaderId"value="$custom_header_id"/><http:headername="Authorization"value="Basicc29tZVVzZXJuYW1lOnNvbWVQYXNzd29yZA=="/></http:headers><http:body><http:data><![CDATA[<testRequestMessage><text>HelloHttpServer</text></testRequestMessage>]]></http:data></http:body></http:POST><http:extract><http:headername="X-MessageId"variable="message_id"/></http:extract></http:receive-request>

<http:send-responseserver="helloHttpServer"><http:headersstatus="200"reason-phrase="OK"version="HTTP/1.1"><http:headername="X-MessageId"value="$message_id"/><http:headername="X-CustomHeaderId"value="$custom_header_id"/><http:headername="Content-Type"value="application/xml"/>

CitrusReferenceGuide

245Http

Page 246: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</http:headers><http:body><http:data><![CDATA[<testResponseMessage><text>HelloCitrus</text></testResponseMessage>]]></http:data></http:body></http:send-response>

WereceiveaclientrequestandvalidatethattherequestmethodisPOSTonrequestpath/test.Nowwecanvalidatespecialmessageheaderssuchascontent-type.Inadditiontothatwecancheckcustomheadersandbasicauthorizationheaders.Asusualtheoptionalmessagebodyiscomparedtoanexpectedmessagetemplate.ThecustomX-MessageIdheaderissavedtoatestvariablemessage_idforlaterusageintheresponse.

TheresponsemessagedefinesHttptypicalentitiessuchasstatusandreason-phrase.Herethetestercansimulate404NOT_FOUNDerrorsorsimilarotherstatuscodesthatgetsendbacktotheclient.InourexampleeverythingisOKandwesendbackaresponsebodyandsomecustomheaderentries.

ThatisbasicallyhowCitrussimulatesHttpserveroperations.Wereceivetheclientrequestandvalidatetherequestproperties.ThenwesendbackaresponsewithaHttpstatuscode.

AsusualalltheseHttpspecificactionsarealsoavailableinJavaDSL.

@CitrusTestpublicvoidhttpServerActionTest()http().server("helloHttpServer").receive().post("/test").payload("<testRequestMessage>"+"<text<HelloHttpServer</text>"+"</testRequestMessage>").contentType("application/xml").accept("application/xml,*/*").header("X-CustomHeaderId","$custom_header_id").header("Authorization","Basicc29tZVVzZXJuYW1lOnNvbWVQYXNzd29yZA==").extractFromHeader("X-MessageId","message_id");

http().server("helloHttpServer")

CitrusReferenceGuide

246Http

Page 247: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

.send().response(HttpStatus.OK).payload("<testResponseMessage>"+"<text<HelloCitrus</text>"+"</testResponseMessage>").version("HTTP/1.1").contentType("application/xml").header("X-CustomHeaderId","$custom_header_id").header("X-MessageId","$message_id");

ThisistheexactsameexampleinJavaDSL.Weselectserveractionsfirstandreceiveclientrequests.ThenwesendbackaresponsewithaHttpStatus.OKstatus.ThiscompletestheserveractionsonHttpmessagetransport.NowwecontinuewithsomemoreHttpspecificsettingsandfeatures.

HTTPheaders

WhendealingwithHTTPrequest/responsecommunicationwealwaysdealwithHTTPspecificheaders.TheHTTPprotocoldefinesagroupofheaderattributesthatbothclientandserverneedtobeabletohandle.YoucansetandvalidatetheseHTTPheadersinCitrusquiteeasy.LetushavealookataclientoperationinCitruswheresomeHTTPheadersareexplicitlysetbeforetherequestissentout.

<http:send-requestclient="httpClient"><http:POST><http:headers><http:headername="X-CustomHeaderId"value="$custom_header_id"/><http:headername="Content-Type"value="text/xml"/><http:headername="Accept"value="text/xml,*/*"/></http:headers><http:body><http:payload><testRequestMessage><text>HelloHttpServer</text></testRequestMessage></http:payload></http:body></http:POST></http:send-request>

Weareabletosetcustomheaders(X-CustomHeaderId)thatgodirectlyintotheHTTPheadersectionoftherequest.InadditiontothattesterscanexplicitlysetHTTPreservedheaderssuchasContent-Type.Fortunatelyyoudonothavetosetallheadersonyour

CitrusReferenceGuide

247Http

Page 248: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

own.CitruswillautomaticallysettherequiredHTTPheadersfortherequest.SowehavethefollowingHTTPrequestwhichissenttotheserver:

POST/testHTTP/1.1Accept:text/xml,*/*Content-Type:text/xmlX-CustomHeaderId:123456789Accept-Charset:macromanUser-Agent:JakartaCommons-HttpClient/3.1Host:localhost:8091Content-Length:175<testRequestMessage><text>HelloHttpServer</text></testRequestMessage>

OnserversidetestersareinterestedinvalidatingtheHTTPheaders.WithinCitrusreceiveactionyousimplydefinetheexpectedheaderentries.TheHTTPspecificheadersareautomaticallyavailableforvalidationasyoucanseeinthisexample:

<http:receive-requestserver="httpServer"><http:POST><http:headers><http:headername="X-CustomHeaderId"value="$custom_header_id"/><http:headername="Content-Type"value="text/xml"/><http:headername="Accept"value="text/xml,*/*"/></http:headers><http:body><http:payload><testRequestMessage><text>HelloHttpServer</text></testRequestMessage></http:payload></http:body></http:POST></http:receive-request>

ThetestchecksoncustomheadersandHTTPspecificheaderstomeettheexpectedvalues.

NowthatwehaveacceptedtheclientrequestandvalidatedthecontentsweareabletosendbackaproperHTTPresponsemessage.SamethingherewithHTTPspecificheaders.TheHTTPprotocoldefinesseveralheadersmarkingthesuccessorfailureoftheserveroperation.InthetestcaseyoucansetthoseheadersfortheresponsemessagewithconventionalCitrusheadernames.Seethefollowingexampletofindouthowthatworksforyou.

CitrusReferenceGuide

248Http

Page 249: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<http:send-responseserver="httpServer"><http:headersstatus="200"reason-phrase="OK"><http:headername="X-CustomHeaderId"value="$custom_header_id"/><http:headername="Content-Type"value="text/xml"/></http:headers><http:body><http:payload><testResponseMessage><text>HelloCitrusClient</text></testResponseMessage></http:payload></http:body></http:send-response>

Oncemorewesetthecustomheaderentry(X-CustomHeaderId)andaHTTPreservedheader(Content-Type)fortheresponsemessage.OntopofthisweareabletosettheresponsestatusfortheHTTPresponse.Weusethereservedheadernamesstatusinordertomarkthesuccessoftheserveroperation.WiththismechanismwecaneasilysimulatedifferentserverbehavioursuchasHTTPerrorresponsecodes(e.g.404-Notfound,500-Internalerror).Letushaveacloserlookatthegeneratedresponsemessage:

HTTP/1.1200OKContent-Type:text/xml;charset=UTF-8Accept-Charset:macromanContent-Length:205Server:Jetty(7.0.0.pre5)<testResponseMessage><text>HelloCitrusClient</text></testResponseMessage>

TipYoudonothavetosetthereasonphraseallthetime.ItissufficienttoonlysettheHTTPstatuscode.CitruswillautomaticallyaddtheproperreasonphraseforwellknownHTTPstatuscodes.

TheonlythingthatismissingrightnowisthevalidationofHTTPstatuscodeswhenreceivingtheserverresponseinaCitrustestcase.ItisveryeasyasyoucanusetheCitrusreservedheadernamesforvalidation,too.

<http:receive-responseclient="httpClient"><http:headersstatus="200"reason-phrase="OK"version="HTTP/1.1"><http:headername="X-CustomHeaderId"value="$custom_header_id"/></http:headers><http:body>

CitrusReferenceGuide

249Http

Page 250: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<http:payload><testResponseMessage><text>HelloTestFramework</text></testResponseMessage></http:payload></http:body></http:receive-response>

UptonowwehaveusedsomeofthebasicCitrusreservedHTTPheadernames(status,version,reason-phrase).InHTTPRESTfulservicessomeotherheadernamesareessentialforvalidation.Thesearerequestattributeslikequeryparameters,contextpathandrequestURI.TheCitrusserversideRESTmessagecontrollerwillautomaticallyaddallthisinformationtothemessageheaderforyou.Soallyouneedtodoisvalidatetheheaderentriesinyourtest.

ThenextexamplereceivesaHTTPGETmethodrequestonserverside.HeretheGETrequestdoesnothaveanymessagepayload,sothevalidationjustworksontheinformationgiveninthemessageheader.Weassumetheclienttocallhttp://localhost:8080/app/users?id=123456789.Asatesterweneedtovalidatetherequestmethod,requestURI,contextpathandthequeryparameters.

<http:receive-requestserver="httpServer"><http:GETpath="/app/users"context-path="/app"><http:params><http:paramname="id"value="123456789"/></http:params><http:headers><http:headername="Host"value="localhost:8080"/><http:headername="Content-Type"value="text/html"/><http:headername="Accept"value="text/xml,*/*"/></http:headers><http:body><http:data></http:data></http:body></http:GET></http:receive-request>

TipBeawareoftheslightdifferencesinrequestURIandcontextpath.Thecontextpathgivesyouthewebapplicationcontextpathwithintheservletcontainerforyourwebapplication.TherequestURIalwaysgivesyouthecompletepaththatwascalledforthisrequest.

CitrusReferenceGuide

250Http

Page 251: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

AsyoucanseeweareabletovalidateallpartsoftheinitialrequestendpointURItheclientwascalling.ThiscompletestheHTTPheaderprocessingwithinCitrus.OnbothclientandserversideCitrusisabletosetandvalidateHTTPspecificheaderentrieswhichisessentialforsimulatingHTTPcommunication.

HTTPserverinterceptors

Theservercomponentisabletoaddcustominterceptorsthatparticipateintherequest/responseprocessing.Theinterceptorsneedtoimplementthecommoninterfaceorg.springframework.web.servlet.HandlerInterceptor.

<citrus-http:serverid="httpServer"port="8080"auto-start="true"interceptors="serverInterceptors"/>

<util:listid="serverInterceptors"><beanclass="com.consol.citrus.http.interceptor.LoggingHandlerInterceptor"/></util:list>

ThesampleaboveaddstheCitruslogginghandlerinterceptorthatlogsrequestsandresponsesexchangedwiththatservercomponent.Youcanaddcustominterceptorimplementationshereinordertoparticipateintherequest/responsemessageprocessing.

HTTPformurlencodeddata

HTMLformdatacanbesenttotheserverusingdifferentmethodsandcontenttypes.OneofthemisaPOSTmethodwithx-www-form-urlencodedbodycontent.Theformdataelementsaresenttotheserverusingkey-valuepairsPOSTdatawheretheformcontrolnameisthekeyandthecontroldataistheurlencodedvalue.

Formurlencodedformdatacontentcouldlooklikethis:

password=s%21cr%21t&username=foo

Ayoucanseetheformdataisautomaticallyencoded.Intheexampleabovewetransmittwoformcontrolspasswordandusernamewithrespectivevaluess$cr$tandfoo.IncasewewouldvalidatethisformdatainCitrusweareabletodothiswithplaintextmessagevalidation.

CitrusReferenceGuide

251Http

Page 252: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<receiveendpoint="httpServer"><messagetype="plaintext"><data><![CDATA[password=s%21cr%21t&username=$username]]></data></message><header><elementname="citrus_http_method"value="POST"/><elementname="citrus_http_request_uri"value="/form-test"/><elementname="Content-Type"value="application/x-www-form-urlencoded"/></header></receive>

Obviouslyvalidatingthesekey-valuepaircharactersequencescanbehardespeciallywhenhavingHTMLformswithlotsofformcontrols.ThisiswhyCitrusprovidesaspecialmessagevalidatorforx-www-form-urlencodedcontents.Firstofallwehavetoaddcitrus-httpmoduleasdependencytoourprojectifnotdonesoyet.AfterthatwecanaddthevalidatorimplementationtothelistofmessagevalidatorsusedinCitrus.

<citrus:message-validators><citrus:validatorclass="com.consol.citrus.http.validation.FormUrlEncodedMessageValidator"/></citrus:message-validators>

Nowweareabletoreceivetheurlencodedformdatamessageinatest.

<receiveendpoint="httpServer"><messagetype="x-www-form-urlencoded"><payload><form-dataxmlns="http://www.citrusframework.org/schema/http/message"><content-type>application/x-www-form-urlencoded</content-type><action>/form-test</action><controls><controlname="password"><value>$password</value></control><controlname="username"><value>$username</value></control></controls></form-data></payload></message><header><elementname="citrus_http_method"value="POST"/>

CitrusReferenceGuide

252Http

Page 253: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<elementname="citrus_http_request_uri"value="/form-test"/><elementname="Content-Type"value="application/x-www-form-urlencoded"/></header></receive>

Weuseaspecialmessagetypex-www-form-urlencodedsothenewmessagevalidatorwilltakeaction.TheformurlencodedmessagevalidatorisabletohandleaspecialXMLrepresentationoftheformdata.ThisenablestheverypowerfulXMLmessagevalidationcapabilitiesofCitrussuchasignoringelementsandusageoftestvariablesinline.

Eachformcontrolistranslatedtoacontrolelementwithrespectivenameandvalueproperties.Theformdataisvalidatedinamorecomfortablewayastheplaintextmessagevalidatorwouldbeabletooffer.

HTTPerrorhandling

SofarwehavereceivedresponsemessageswithHTTPstatuscode200OK.Howtodealwithservererrorslike404NotFoundor500Internalservererror?ThedefaultHTTPmessageclienterrorstrategyistopropagateservererrorresponsemessagestothereceiveactionforvalidation.WesimplycheckonHTTPstatuscodeandstatustextforerrorvalidation.

<http:send-requestclient="httpClient"><http:body><http:payload><testRequestMessage><text>HelloHttpServer</text></testRequestMessage></http:payload></http:body></http:send-request>

<http:receive-requestclient="httpClient"><http:body><http:data><![CDATA[]]></http:data></http:body><http:headersstatus="403"reason-phrase="FORBIDDEN"/></http:receive>

Themessagedatacanbeemptydependingontheserverlogicfortheseerrorsituations.Ifwereceiveadditionalerrorinformationasmessagepayloadjustaddvalidationassertionsasusual.

CitrusReferenceGuide

253Http

Page 254: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

InsteadofreceivingsuchemptymessageswithchecksonHTTPstatusheaderinformationwecanchangetheerrorstrategyinthemessagesendercomponentinordertoautomaticallyraiseexceptionsonresponsemessagesotherthan200OK.ThereforewegobacktotheHTTPmessagesenderconfigurationforchangingtheerrorstrategy.

<citrus-http:clientid="httpClient"request-url="http://localhost:8080/test"error-strategy="throwsException"/>

Nowweexpectanexceptiontobethrownbecauseoftheerrorresponse.Followingfromthatwehavetochangeourtestcase.InsteadofreceivingtheerrormessagewithreceiveactionweasserttheclientexceptionandcheckontheHTTPstatuscodeandstatustext.

<assertexception="org.springframework.web.client.HttpClientErrorException"message="403Forbidden"><when><http:send-requestclient="httpClient"><http:body><http:payload><testRequestMessage><text>HelloHttpServer</text></testRequestMessage></http:payload></http:body></http:send-request></when></assert>

BothwaysofhandlingHTTPerrormessagesonclientsidearevalidforexpectingtheservertoraiseHTTPerrorcodes.Choosethepreferredwayaccordingtoyourtestprojectrequirements.

HTTPclientbasicauthentication

Asclientyoumayhavetousebasicauthenticationinordertoaccessaresourceontheserver.Inmostcasesthiswillbeusername/passwordauthenticationwherethecredentialsaretransmittedintherequestheadersectionasbase64encoding.

TheeasiestapproachtosettheAuthorizationheaderforabasicauthenticationHTTPrequestwouldbetosetitonyourowninthesendactiondefinition.Ofcourseyouhavetousethecorrectbasicauthenticationheadersyntaxwithbase64encodingforthe

CitrusReferenceGuide

254Http

Page 255: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

username:passwordphrase.Seethissimpleexample.

<http:headers><http:headername="Authorization"value="Basicc29tZVVzZXJuYW1lOnNvbWVQYXNzd29yZA=="/></http:headers>

CitruswilladdthisheadertotheHTTPrequestsandtheserverwillreadtheAuthorizationusernameandpassword.Formoreconvenientbase64encodingyoucanalsouseaCitrusfunction,seefunctions-encode-base64

NowthereisamorecomfortablewaytosetthebasicauthenticationheaderinalltheCitrusrequests.AsCitrususesSpring'sRESTsupportwiththeRestTemplateandClientHttpRequestFactorythebasicauthenticationisalreadycoveredthereinamoregenericway.YousimplyhavetoconfigurethebasicauthenticationcredentialsontheRestTemplate'sClientHttpRequestFactory.Justseethefollowingexampleandlearnhowtodothat.

<citrus-http:clientid="httpClient"request-method="POST"request-url="http://localhost:8080/test"request-factory="basicAuthFactory"/>

<beanid="basicAuthFactory"class="com.consol.citrus.http.client.BasicAuthClientHttpRequestFactory"><propertyname="authScope"><beanclass="org.apache.http.auth.AuthScope"><constructor-argvalue="localhost"/><constructor-argvalue="8072"/><constructor-argvalue=""/><constructor-argvalue="basic"/></bean></property><propertyname="credentials"><beanclass="org.apache.http.auth.UsernamePasswordCredentials"><constructor-argvalue="someUsername"/><constructor-argvalue="somePassword"/></bean></property></bean>

Theadvantagesofthismethodisobvious.Nowallsendingtestactionsthatreferencetheclientcomponentwillautomaticallyaddthebasicauthenticationheader.

CitrusReferenceGuide

255Http

Page 256: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ImportantSinceCitrushasupgradedtoSpring3.1.xtheJakartacommonsHTTPclientisdeprecatedwithCitrusversion1.2.TheformerlyusedUserCredentialsClientHttpRequestFactoryisthereforealsodeprecatedandwillnotcontinuewithnextversions.PleaseupdateyourconfigurationifyouarecomingfromCitrus1.1orearlierversions.

TheaboveconfigurationresultsinHTTPclientrequestswithauthenticationheadersproperlysetforbasicauthentication.TheclientrequestfactorytakescareonaddingtheproperbasicauthenticationheadertoeachrequestthatissentwiththisCitrusmessagesender.Citrususespreemtiveauthentication.Themessagesenderonlysendsasinglerequesttotheserverwithallauthenticationinformationsetinthemessageheader.Therequestwhichdeterminestheauthenticationschemeontheserverisskipped.ThisiswhyyouhavetoaddsomeauthscopeintheclientrequestfactorysoCitruscansetupanauthenticationcachewithintheHTTPcontextinordertohavepreemtiveauthentication.

AsaresultofthebasicauthclientrequestfactorythefollowingexamplerequestthatiscreatedbytheCitrusHTTPclienthastheAuthorizationheaderset.ThisisdonenowautomaticallyforallrequestswiththisHTTPclient.

POST/testHTTP/1.1Accept:text/xml,*/*Content-Type:text/xmlAccept-Charset:iso-8859-1,us-ascii,utf-8Authorization:Basicc29tZVVzZXJuYW1lOnNvbWVQYXNzd29yZA==User-Agent:JakartaCommons-HttpClient/3.1Host:localhost:8080Content-Length:175<testRequestMessage><text>HelloHttpServer</text></testRequestMessage>

HTTPserverbasicauthentication

Citrusasaservercanalsosetbasicauthenticationsoclientsneedtoauthenticateproperlywhenaccessingserverresources.

<citrus-http:serverid="basicAuthHttpServer"port="8090"auto-start="true"resource-base="src/it/resources"security-handler="basicSecurityHandler"/>

CitrusReferenceGuide

256Http

Page 257: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<beanid="securityHandler"class="com.consol.citrus.http.security.SecurityHandlerFactory"><propertyname="users"><list><beanclass="com.consol.citrus.http.security.User"><propertyname="name"value="citrus"/><propertyname="password"value="secret"/><propertyname="roles"value="CitrusRole"/></bean></list></property><propertyname="constraints"><map><entrykey="/foo/*"><beanclass="com.consol.citrus.http.security.BasicAuthConstraint"><constructor-argvalue="CitrusRole"/></bean></entry></map></property></bean>

Wehavesetasecurityhandlerontheserverwebcontainerwithaconstraintonallresourceswith/foo/*.Followingfromthattheserverrequiresbasicauthenticationfortheseresources.Thegrantedusersandrolesarespecifiedwithinthesecurityhandlerbeandefinition.ConnectingclientshavetosetthebasicauthHTTPheaderproperlyusingthecorrectuserandroleforaccessingtheCitrusservernow.

Youcancustomizethesecurityhandlerforyourveryspecificneeds(e.g.loadusersandroleswithJDBCfromadatabase).Justhavealookatthecodebaseandinspectthesettingsandpropertiesofferedbythesecurityhandlerinterface.

TipThismechanismisnotrestrictedtobasicauthenticationonly.Withothersettingsyoucanalsosetupdigestorform-basedauthenticationconstraintsveryeasy.

HTTPGzipcompression

Gzipisaverypopularcompressionmechanismforoptimizingthemessagetransportationforlargecontent.TheCitrushttpclientandservercomponentssupportgzipcompressionoutofthebox.Thismeansthatyouonlyneedtosetthespecificencodingheadersinyourhttprequest/responsemessage.

Accept-Encoding=gzipSettingforclientswhenrequestinggzipcompressedresponsecontent.TheHttpservermustsupportgzipcompressiontheninordertoprovidetheresponseaszippedbytestream.TheCitrushttpservercomponentautomaticallyrecognizesthisheaderinarequestandappliesgzipcompressionto

CitrusReferenceGuide

257Http

Page 258: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

theresponse.Content-Encoding=gzipWhenahttpserversendscompressedmessagecontenttotheclientthisheaderissettogzipinordertomarkthecompression.TheHttpclientmustsupportgzipcompressiontheninordertounzipthemessagecontent.TheCitrushttpclientcomponentautomaticallyrecognizesthisheaderinaresponseandappliesgzipunziplogicbeforepassingthemessagetothetestcase.

TheCitrusclientandserverautomaticallytakecareongzipcompressionwhenthoseheadersareset.Inthetestcaseyoudonotneedtoziporunzipthecontentthenasitisautomaticallydonebefore.

ThismeansthatyoucanrequestgzippedcontentfromaserverwithjustaddingthemessageheaderAccept-Encodinginyourhttprequestoperation.

<echo><message>SendHttpclientrequestforgzipcompresseddata</message></echo>

<http:send-requestclient="gzipClient"><http:POST><http:headerscontent-type="text/html"><http:headername="Accept-Encoding"value="gzip"/><http:headername="Accept"value="text/plain"/></http:headers></http:POST></http:send-request>

<echo><message>Receivetextautomaticallygzipunzipped</message></echo>

<http:receive-responseclient="gzipClient"><http:headersstatus="200"reason-phrase="OK"><http:headername="Content-Type"value="text/plain"/></http:headers><http:bodytype="plaintext"><http:data>$text</http:data></http:body></http:receive-response>

OntheserversideifwereceiveamessageandtheresponseshouldbecompressedwithGzipwejusthavetosettheContent-Encodingheaderintheresponseoperation.

<echo><message>Receivegzipcompressedasbase64encodedtext</message></echo>

CitrusReferenceGuide

258Http

Page 259: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<http:receive-requestserver="echoHttpServer"><http:POSTpath="/echo"><http:headers><http:headername="Content-Type"value="text/html"/><http:headername="Accept-Encoding"value="gzip"/><http:headername="Accept"value="text/plain"/></http:headers></http:POST></http:receive-request>

<echo><message>SendHttpservergzipcompressedresponse</message></echo>

<http:send-responseserver="echoHttpServer"><http:headersstatus="200"reason-phrase="OK"><http:headername="Content-Encoding"value="gzip"/><http:headername="Content-Type"value="text/plain"/></http:headers><http:body><http:data>$text</http:data></http:body></http:send-response>

SotheCitrusserverwillautomaticallyaddgzipcompressiontotheresponseforus.

Ofcourseyoucanalsosendgzippedcontentasaclient.ThenyouwouldjustsettheContent-Encodingheadertogzipinyourrequest.Theclientwillautomaticallyapplycompressionforyou.

HTTPservletcontextcustomization

TheCitrusHTTPserverusesSpringapplicationcontextloadingonstartup.ForhighcustomizationsyoucanprovideacustomservletcontextfilewhichholdsallcustomconfigurationsasSpringbeansfortheserver.HereisasampleservletcontextwithsomebasicSpringMVCcomponentsandthecentralHttpMessageControllerwhichisresponsibleforhandlingincomingrequests(GET,PUT,DELETE,POST,etc.).

<beanid="citrusHandlerMapping"class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"

<beanid="citrusMethodHandlerAdapter"class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"<propertyname="messageConverters"><util:listid="converters"><beanclass="org.springframework.http.converter.StringHttpMessageConverter"><propertyname="supportedMediaTypes"><util:list>

CitrusReferenceGuide

259Http

Page 260: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<value>text/xml</value></util:list></property></bean></util:list></property></bean>

<beanid="citrusHttpMessageController"class="com.consol.citrus.http.controller.HttpMessageController"<propertyname="endpointAdapter"><beanclass="com.consol.citrus.endpoint.adapter.EmptyResponseEndpointAdapter"/></property></bean>

ThebeansaboveareresponsibleforproperHTTPserverconfiguration.Ingeneralyoudonotneedtoadjustthosebeans,butwehavethepossibilitytodosowhichgivesusagreatcustomizationandextensionpoints.TheimportantpartistheendpointadapterdefinitioninsidetheHttpMessageController.Onceaclientrequestwasacceptedtheadapterisresponsibleforgeneratingaproperresponsetotheclient.

YoucanaddthecustomservletcontextasfileresourcetotheCitrusHTTPservercomponent.Justusethecontext-config-locationattributeasfollows:

<citrus-http:serverid="helloHttpServer"port="8080"auto-start="true"context-config-location="classpath:com/consol/citrus/http/custom-servlet-context.xml"resource-base="src/it/resources"/>

CitrusReferenceGuide

260Http

Page 261: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

WebSocketsupportTheWebSocketmessageprotocolbuildsontopofHttpstandardandbringsbidirectionalcommunicationtotheHttpclient-serverworld.CitrusisabletosendandreceivemessageswithWebSocketconnectionsasclientandserver.TheHttpserverimplementationisnowabletodefinemultipleWebSocketendpoints.ThenewCitrusWebSocketclientisabletopublishandconsumermessagesviabidirectionalWebSocketprotocol.

ThenewWebSocketsupportislocatedinthemodulecitrus-websocket.ThereforeweneedtoaddthismoduletoourprojectasdependencywhenweareabouttousetheWebSocketfeaturesinCitrus.

<dependency><groupId>com.consol.citrus</groupId><artifactId>citrus-websocket</artifactId><version>2.7.1</version></dependency>

AsCitrusprovidesacustomizedWebSocketconfigurationschemafortheSpringapplicationcontextconfigurationfileswehavetoaddnametothetoplevelbeanselement.Simplyincludethewebsocket-confignamespaceintheconfigurationXMLfilesasfollows.

<beansxmlns="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-websocket="http://www.citrusframework.org/schema/websocket/config"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/confighttp://www.citrusframework.org/schema/config/citrus-config.xsdhttp://www.citrusframework.org/schema/websocket/confighttp://www.citrusframework.org/schema/websocket/config/citrus-websocket-config.xsd"

[...]

</beans>

CitrusReferenceGuide

261HttpWebsockets

Page 262: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

NowourprojectisreadytousetheCitrusWebSocketsupport.FirstofallletussendamessageviaWebSocketconnectiontosomeserver.

WebSocketclient

OntheclientsideCitrusoffersaclientcomponentthatgoesdirectlytotheSpringbeanapplicationcontext.Theclientneedsaserverendpointuri.ThisisaWebSocketprotocolendpointuri.

<citrus-websocket:clientid="helloWebSocketClient"url="http://localhost:8080/hello"timeout="5000"/>

Theurldefinestheendpointtosendmessagesto.TheserverhastobeaWebSocketreadywebserverthatsupportsHttpconnectionupgradeforWebSocketprotocols.WebSocketbyitsnatureisanasynchronousbidirectionalprotocol.Thismeansthattheconnectionbetweenclientandserverremainsopenandbothserverandclientcansendandreceivemessages.SowhentheCitrusclientiswaitingforamessageweneedatimeoutthatstopstheasynchronouswaiting.Thereceivingtestactionandthetestcasewillfailwhensuchatimeoutisraised.

TheWebSocketclientwillautomaticallyopenaconnectiontotheserverandaskforaconnectionupgradetoWebSocketprotocol.Thishandshakeisdoneoncewhentheconnectiontotheserverisestablished.Afterthattheclientcanpushmessagestotheserverandontheothersidetheservercanpushmessagestotheclient.Nowletsfirstpushsomemessagestotheserver:

<sendendpoint="helloWebSocketClient"><message><payload><TestMessage><Text>HelloWebSocketServer</Text></TestMessage></payload></message></send>

Theconnectionhandshakeandtheconnectionupgradeisdoneautomaticallybytheclient.Afterthatthemessageispushedtotheserver.AsWebSocketisabidirectionalprotocolwecanalsoreceivemessagesontheWebSocketclient.Thesemessagesarepushedfromservertoallconnectedclients.

CitrusReferenceGuide

262HttpWebsockets

Page 263: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<receiveendpoint="helloWebSocketClient"><message><payload><TestMessage><Text>HelloWebSocketClient</Text></TestMessage></payload></message></receive>

Wejustusetheverysameclientendpointcomponentinamessagereceiveaction.Theclientwillwaitformessagesfromtheserverandoncereceivedperformthewellknownmessagevalidation.HereweexpectsomeXMLmessagepayload.ThiscompletestheclientsideasweareabletopushandconsumermessagesviaWebSocketconnections.

TipUptonowwehaveusedstaticWebSocketendpointURIsinourclientcomponentconfigurations.ThiscanbedonewithamorepowerfuldynamicendpointURIinWebSocketclient.SimilartotheendpointresolvingmechanisminSOAPyoucandynamicallysetthecalledendpointuriattestruntimethroughmessageheadervalues.BydefaultCitruswillcheckaspecificheaderentryfordynamicendpointURIwhichissimplydefinedforeachmessagesendingactioninsidethetest.

ThedynamicEndpointResolverbeanmustimplementtheEndpointUriResolverinterfaceinordertoresolvedynamicendpointurivalues.Citrusoffersadefaultimplementation,theDynamicEndpointUriResolver,whichusesaspecificmessageheaderforsettingdynamicendpointuri.Themessageheaderneedstospecifytheheadercitrus_endpoint_uriwithavalidrequesturi.

<header><elementname="citrus_endpoint_uri"value="ws://localhost:8080/customers/$customerId"</header>

Thespecificsendactionabovewillsenditsmessagetothedynamicendpoint(ws://localhost:8080/customers/$customerId)whichissetintheheadercitrus_endpoint_uri.

WebSocketserverendpoints

CitrusReferenceGuide

263HttpWebsockets

Page 264: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

OntheserversideCitrushasaHttpserverimplementationthatwecaneasilystartduringtestruntime.TheHttpserveracceptsconnectionsfromclientsandalsosupportsWebSocketupgradestrategies.ThismeansclientscanaskforaupgradetotheWebSocketstandard.InthishandshaketheserverwillupgradetheconnectiontoWebSocketandafterwardsclientandservercanexchangemessagesoverthisconnection.Thismeanstheconnectioniskeptaliveandmultiplemessagescanbeexchanged.LetsseehowWebSocketendpointsareaddedtoaHttpservercomponentinCitrus.

<citrus-websocket:serverid="helloHttpServer"port="8080"auto-start="true"resource-base="src/it/resources"><citrus-websocket:endpoints><citrus-websocket:endpointref="websocket1"/><citrus-websocket:endpointref="websocket2"/></citrus-websocket:endpoints></citrus-websocket:server>

<citrus-websocket:endpointid="websocket1"path="/test1"/><citrus-websocket:endpointid="websocket2"path="/test2"timeout="10000"/>

TheembeddedJettyWebSocketservercomponentinCitrusnowisabletodefinemultipleWebSocketendpoints.TheWebSocketendpointsmatchtoarequestpathontheserverandarereferencedbyauniqueid.EachWebSocketendpointcanfollowindividualtimeoutsettings.Inatestwecanusetheseendpointsdirectlytoreceivemessages.

<testcasename="httpWebSocketServerTest"><actions><receiveendpoint="websocket1"><message><data>[...]</data></message></receive>

<sendendpoint="websocket1"><message><data>[...]</data></message></send>

CitrusReferenceGuide

264HttpWebsockets

Page 265: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</actions></testcase>

Asyoucanseewereferencetheendpointidinbothreceiveandsendactions.EachWebSocketendpointholdsoneormoreopenconnectionstoitsclients.Eachmessagethatissentispushedtoallconnectedclients.EachclientcansendmessagestotheWebSocketendpoint.

TheWebSocketendpointcomponenthandlesconnectionhandshakesautomaticallyandcachesallopensessionsinmemory.Bydefaultallconnectedclientswillreceivethemessagespushedfromserver.Thisisdonecompletelybehindthescenes.TheCitrusserverisabletohandlemultipleWebSocketendpointswithdifferentclientsconnectedtoitatthesametime.ThisiswhywehavetochoosetheWebSocketendpointontheserverbyitsidentifierwhensendingandreceivingmessages.

WiththisWebSocketendpointswechangetheCitrusserverbehaviorsothatclientscanupgradetoWebSocketconnection.Nowwehaveabidirectionalconnectionwheretheservercanpushmessagestotheclientandviceversa.

WebSocketheaders

TheWebSocketstandarddefinessomedefaultheaderstouseduringconnectionupgrade.Theseheadersaremadeavailabletothetestcaseinbothdirections.CitruswillhandletheseheadervalueswithspecialcarewhenWebSocketsupportisactivatedonaserverorclient.NowWebSocketmessagescanalsobesplitintomultiplepieces.Eachmessagepartispushedseparatelytotheserverbutstillisconsideredtobeasinglemessagepayload.TheserverhastocollectandaggregateallmessagesuntilaspecialmessageheaderisLastissetinoneofthemessageparts.

TheCitrusWebSocketclientcanslicemessagesintoseveralparts.

<sendendpoint="webSocketClient"><messagetype="json"><data>["event":"client_message_1","timestamp":"citrus:currentDate()",</data></message><header><elementname="citrus_websocket_is_last"value="false"/>

CitrusReferenceGuide

265HttpWebsockets

Page 266: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</header></send>

<sleepmilliseconds="500"/>

<sendendpoint="webSocketClient"><messagetype="json"><data>"event":"client_message_2","timestamp":"citrus:currentDate()"]</data></message><header><elementname="citrus_websocket_is_last"value="true"/></header></send>

ThetestabovehastwoseparatesendoperationsbothsendingtoaWebSocketendpoint.Thefirstsendingactionsetstheheadercitrus_websocket_is_lasttofalsewhichindicatesthatthemessageisnotcompleteyet.The2ndsendactionpushestherestofthemessagetotheserverandsetthecitrus_websocket_is_lastheadertotrue.Nowtheserverisabletoaggregatethemessagepiecestoasinglemessagepayload.TheresultisavalidaJSONarraywithbotheventsinit.

["event":"client_message_1","timestamp":"2015-01-01","event":"client_message_2","timestamp":"2015-01-01"]

NowtheserverpartinCitrusisabletohandletheseslicedmessages,too.Theserverwillautomaticallyaggregatethosemessagepartsbeforepassingittothetestcaseforvalidation.

CitrusReferenceGuide

266HttpWebsockets

Page 267: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

SOAPWebServicesSOAPWebServicesoverHTTPisawidelyusedcommunicationscenarioinmodernenterpriseapplications.ASOAPWebServiceclientispostingaSOAPrequestviaHTTPtoaserver.SOAPviaHTTPisasynchronousmessageprotocolbydefaultsotheclientiswaitingsynchronouslyfortheresponsemessage.CitrusprovidesbothSOAPclientandservercomponentsinordertomeetbothdirectionsofthisscenario.ThecomponentsusedareverysimilartotheHTTPcomponentsthatwerehavediscussedinthesectionsbefore.

NoteTheSOAPWebServicecomponentsinCitrusarekeptinaseparateMavenmodule.SoyoushouldaddthemoduleasMavendependencytoyourprojectaccordingly.

<dependency><groupId>com.consol.citrus</groupId><artifactId>citrus-ws</artifactId><version>2.7.1</version></dependency>

InordertousetheSOAPWebServicesupportyouneedtoincludethespecificXMLconfigurationschemaprovidedbyCitrus.SeefollowingXMLdefinitiontofindouthowtoincludethecitrus-wsnamespace.

<beansxmlns="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-ws="http://www.citrusframework.org/schema/ws/config"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/confighttp://www.citrusframework.org/schema/config/citrus-config.xsdhttp://www.citrusframework.org/schema/ws/confighttp://www.citrusframework.org/schema/ws/config/citrus-ws-config.xsd">

[...]

</beans>

CitrusReferenceGuide

267Soap

Page 268: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Nowyouarereadytousethecustomizedsoapconfigurationelements-allusingthecitrus-wsprefix-inyourSpringconfiguration.

SOAPclient

CitrusisabletoformaproperSOAPrequestinordertopassittotheserverviaHTTPandvalidatetherespectiveSOAPresponsemessage.LetusseehowamessageclientforSOAPlookslikeintheSpringconfiguration:

<citrus-ws:clientid="soapClient"request-url="http://localhost:8090/test"timeout="60000"/>

Theclientcomponentusestherequest-urlinordertoaccesstheserverresource.TheclientwillautomaticallybuildaproperSOAPrequestmessageincludingtheSOAPenvelope,SOAPheaderandthemessagepayloadasSOAPbody.ThismeansthatyouasatesterdonotcareaboutSOAPenvelopespecificlogicinthetestcase.TheclientendpointcomponentsavesthesynchronousSOAPresponsesothetestcasecanreceivethismessagewithanormalreceivetestaction.

IndetailyouasatesterjustsendandreceiveusingthesameclientendpointreferencejustasyouwoulddowithasynchronousJMSorchannelcommunication.IncasenoresponsemessageisavailableintimeaccordingtothetimeoutsettingsCitrusraisesatimeouterrorandthetestwillfail.

ImportantTheSOAPclientcomponentusesaSoapMessageFactoryimplementationinordertocreatetheSOAPmessages.ThisisaSpringbeanaddedtotheCitrusSpringapplicationcontext.Springoffersseveralreferenceimplementationsasmessagefactoriessoyoucanchooseoneofthem(e.g.forSOAP1.1or1.2implementations).

<!--DefaultSOAPMessageFactory(SOAP1.1)--><beanid="messageFactory"class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>

<!--SOAP1.2MessageFactory--><beanid="soap12MessageFactory"class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"<propertyname="soapVersion"><util:constantstatic-field="org.springframework.ws.soap.SoapVersion.SOAP_12"/></property></bean>

CitrusReferenceGuide

268Soap

Page 269: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

BydefaultCitruswillsearchforabeanwithid'messageFactory'.IncaseyouintendtousedifferentidentifiersyouneedtotelltheSOAPclientcomponentwhichmessagefactorytouse:

<citrus-ws:clientid="soapClient"request-url="http://localhost:8090/test"message-factory="soap12MessageFactory"/>

TipUptonowwehaveusedastaticendpointrequesturlfortheSOAPmessagesender.Besidesthatwecanusedynamicendpointuriinconfiguration.Wejustuseanendpointuriresolverinsteadofthestaticrequesturllikethis:

<citrus-ws:clientid="soapClient"endpoint-resolver="dynamicEndpointResolver"message-factory="soap12MessageFactory"/>

<beanid="dynamicEndpointResolver"class="com.consol.citrus.endpoint.resolver.DynamicEndpointUriResolver"/>

ThedynamicEndpointResolverbeanmustimplementtheEndpointUriResolverinterfaceinordertoresolvedynamicendpointurivalues.Citrusoffersadefaultimplementation,theDynamicEndpointUriResolver,whichusesaspecificmessageheaderforsettingthedynamicendpointuriforeachmessage.Themessageheaderneedstospecifytheheadercitrus_endpoint_uriwithavalidrequesturi.Justlikethis:

<header><elementname="citrus_endpoint_uri"value="http://localhost:$port/$context"/></header>

Asyoucanseeyoucanusedynamictestvariablestheninordertobuildtherequesturitouse.TheSOAPclientevaluatestheendpointuriheaderandsendsthemessagetothisserverresource.Youcanuseadifferenturivaluethenindifferenttestcasesandsendactions.

SOAPclientinterceptors

Theclientcomponentisabletoaddcustominterceptorsthatparticipateintherequest/responseprocessing.Theinterceptorsneedtoimplementthecommoninterfaceorg.springframework.ws.client.support.interceptor.ClientInterceptor.

CitrusReferenceGuide

269Soap

Page 270: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<citrus-ws:clientid="secureSoapClient"request-url="http://localhost:8080/services/ws/todolist"interceptors="clientInterceptors"/>

<util:listid="clientInterceptors"><beanclass="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor"><propertyname="securementActions"value="TimestampUsernameToken"/><propertyname="securementUsername"value="admin"/><propertyname="securementPassword"value="secret"/></bean><beanclass="com.consol.citrus.ws.interceptor.LoggingClientInterceptor"/></util:list>

ThesampleaboveaddsWss4JWsSecurityinterceptorsinordertoaddsecurityconstraintstotherequestmessages.

NoteWhencustomizingtheinterceptorchainalldefaultinterceptors(likelogginginterceptor)arelost.Youneedtoaddtheseinterceptorsexlicitlyasshownwiththecom.consol.citrus.ws.interceptor.LoggingClientInterceptorwhichisabletologrequest/responsemessagesduringcommunication.

SOAPserver

Everyclientneedaservertotalkto.WhenreceivingSOAPmessageswerequireawebserverinstancelisteningonaport.CitrusisusinganembeddedJettyserverinstanceincombinationwiththeSpringWebServiceAPIinordertoacceptSOAPrequestcallsasaserver.SeehowtheCitrusSOAPserverisconfiguredintheSpringconfiguration.

<citrus-ws:serverid="helloSoapServer"port="8080"auto-start="true"resource-base="src/it/resources"/>

Theservercomponentisabletostartautomaticallywhenapplicationstartsup.Intheexampleabovetheserverislisteningforrequestsonport8080.ThissetupusesthestandardconnectorconfigurationfortheJettyserver.FordetailedcustomizationtheCitrusJettyserverconfigurationalsosupportsexplicitconnectorconfigurations(@connectorand@connectorsattributes).FormoreinformationpleaseseetheJettyconnectordocumentation.

Testcasesinteractwiththisserverinstanceviamessagechannelsbydefault.Theservercomponentprovidesaninboundchannelthatholdsincomingrequestmessages.Thetestcasecanreceivethoserequestsfromthechannelwithanormalreceivetest

CitrusReferenceGuide

270Soap

Page 271: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

action.InasecondstepthetestcasecanprovideasynchronousresponsemessageasreplywhichwillbeautomaticallysentbacktothecallingSOAPclientasresponse.

Thefigureaboveshowsthebasicsetupwithinboundchannelandreplychannel.Youasatestershouldnotworryaboutthistomuch.Bydefaultyouasatesterjustusetheserverassynchronousendpointinyourtestcase.Thismeansthatyousimplyreceiveamessagefromtheserverandsendaresponseback.

<testcasename="soapServerTest"><actions><receiveendpoint="helloSoapServer"><message><data>[...]</data></message></receive>

<sendendpoint="helloSoapServer"><message><data>[...]</data></message></send></actions></testcase>

Asyoucanseewereferencetheserveridinbothreceiveandsendactions.TheCitrusserverinstancewillautomaticallysendtheresponsebacktothecallingclient.InmostcasesthisiswhatyouneedtosimulateaSOAPserverinstanceinCitrus.Ofcoursewehavesomemorecustomizationpossibilitiesthatwewillgooverlateron.ThiscustomizationsareoptionalsoyoucanalsoskipthenextdescriptiononendpointadaptersifyouarehappywithjustwhatyouhavelearnedabouttheSOAPservercomponentinCitrus.

JustliketheHTTPservercomponenttheSOAPservercomponentbydefaultusesthechannelendpointadapterinordertoforwardallincomingrequeststoaninmemorymessagechannel.Thisisdonecompletelybehindthescenes.TheCitrusconfiguration

CitrusReferenceGuide

271Soap

Page 272: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

hasbecomealoteasierheresoyoudonothavetoconfigurethisbydefault.Whennothingelseissetthetestcasedoesnotworryaboutthatsettingsontheserverandjustusestheserveridreferenceassynchronousendpoint.

TipThedefaultchannelendpointadapterautomaticallycreatesaninboundmessagechannelwhereincomingmessagesarestoredtointernally.Soifyouneedtocleanupaserverthathasalreadystoredsomeincomingmessagesyoucandothiseasilybypurgingtheinternalmessagechannel.ThemessagechannelfollowsanamingconventionserverName.inboundwhereserverNameistheSpringbeannameoftheCitrusserverendpointcomponent.Ifyoupurgethisinternalchannelinabeforetestnatureyouaresurethatobsoletemessagesonaserverinstancegetpurgedbeforeeachtestisexecuted.

HoweverwedonotwanttoloosethegreatextendabilityandcustomizingcapabilitiesoftheCitrusservercomponent.ThisiswhyyoucanoptionallydefinetheendpointadapterimplementationusedbytheCitrusSOAPserver.Weprovideseveralmessageendpointadapterimplementationsfordifferentsimulationstrategies.WiththeseendpointadaptersyoushouldbeabletogenerateproperSOAPresponsemessagesfortheclientinvariousways.Beforewehaveacloserlookatthedifferentadapterimplementationswewanttoshowhowyoucansetacustomendpointadapterontheservercomponent.

<citrus-ws:serverid="helloSoapServer"port="8080"auto-start="true"endpoint-adapter="emptyResponseEndpointAdapter"resource-base="src/it/resources"/>

<citrus:empty-response-adapterid="emptyResponseEndpointAdapter"/>

WiththisendpointadapterconfigurationabovewechangetheCitrusserverbehaviorfromscratch.NowtheserverautomaticallysendsbackanemptySOAPresponsemessageeverytime.SettingacustomendpointadapterimplementationwithcustomlogiciseasyasdefiningacustomendpointadapterSpringbeanandreferenceitintheserverattribute.Youcanreadmoreaboutendpointadaptersinendpoint-adapter.

SOAPsendandreceive

Citrusprovidestestactionsforsendingandreceivingmessagesofallkind.Differentmessagecontentanddifferentmessagetransportsareavailabletothesesendandreceiveactions.WhenusingSOAPmessagetransportwemightneedtosetspecial

CitrusReferenceGuide

272Soap

Page 273: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

informationonthatmessages.ThesearespecialSOAPheaders,SOAPfaultsandsoon.SowehavecreatedaspecialSOAPnamespaceforallyourSOAPrelatedsendandreceiveoperationsinaXMLDSLtest:

<spring:beansxmlns="http://www.citrusframework.org/schema/testcase"xmlns:spring="http://www.springframework.org/schema/beans"xmlns:ws="http://www.citrusframework.org/schema/ws/testcase"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/testcasehttp://www.citrusframework.org/schema/testcase/citrus-testcase.xsdhttp://www.citrusframework.org/schema/ws/testcasehttp://www.citrusframework.org/schema/ws/testcase/citrus-ws-testcase.xsd">

Onceyouhaveaddedthewsnamespacefromabovetoyourtestcaseyouarereadytousespecialsendandreceiveoperationsinthetest.

XMLDSL

<ws:sendendpoint="soapClient"soap-action="MySoapService/sayHello"><message>[...]</message></ws:send>

<ws:receiveendpoint="soapServer"soap-action="MySoapService/sayHello"><message>[...]</message></ws:receive>

Thespecialnamespacecontainsfollowingelements:

send:SpecialsendoperationforsendingoutSOAPmessagecontent.receive:SpecialreceiveoperationforvalidatingSOAPmessagecontent.send-fault:SpecialsendoperationforsendingoutSOAPfaultmessagecontent.assert-fault:SpecialassertionoperationforexpectingaSOAPfaultmessageasresponse.

ThespecialSOAPrelatedsendandreceiveactionscancoexistwithnormalCitrusactions.Infactyoucanmixthoseactiontypesasyouwantinsideofatestcase.AlltestactionsthatworkwithSOAPmessagecontentonclientandserversideshouldusethisspecialnamespace.

CitrusReferenceGuide

273Soap

Page 274: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

InJavaDSLwehavesomethingsimilartothat.TheJavaDSLprovidesspecialSOAPrelatedfeatureswhencallingthesoap()method.WithafluentAPIyouareabletothensendandreceiveSOAPmessagecontentasclientandserver.

JavaDSL

@CitrusTestpublicvoidsoapTest()

soap().client("soapClient").send().soapAction("MySoapService/sayHello").payload("...");

soap().client("soapClient").receive().payload("...");

InthefollowingsectionstheSOAPrelatedcapabilitiesarediscussedinmoredetail.

SOAPheaders

SOAPdefinesseveralheadervariationsthatwediscussinthefollowingsections.FirstofallwedealwiththespecialSOAPactionheader.IncaseweneedtosetthisSOAPactionheaderwesimplyneedtousethespecialsoap-actionattributeinourtest.ThespecialheaderkeyincombinationwithaunderlyingSOAPclientendpointcomponentconstructstheSOAPactionintheSOAPmessage.

XMLDSL

<ws:sendendpoint="soapClient"soap-action="MySoapService/sayHello"><message>[...]</message></ws:send>

<ws:receiveendpoint="soapServer"soap-action="MySoapService/sayHello"><message>[...]</message></ws:receive>

JavaDSL

CitrusReferenceGuide

274Soap

Page 275: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

@CitrusTestpublicvoidsoapActionTest()

soap().client("soapClient").send().soapAction("MySoapService/sayHello").payload("...");

soap().server("soapClient").receive().soapAction("MySoapService/sayHello").payload("...");

TheSOAPactionheaderisaddedtothemessagebeforesendingandvalidatedwhenusedinareceiveoperation.

NoteThesoap-actionattributeisdefinedinthespecialSOAPnamespaceinCitrus.WerecommendtousethisnamespaceforallyoursendandreceiveoperationsthatdealwithSOAPmessagecontent.HoweveryoucanalsosetthespecialSOAPactionheaderwhennotusingthespecialSOAPnamespace:Justsetthisheaderinyourtestaction:

<header><elementname="citrus_soap_action"value="sayHello"/></header>

SecondlyaSOAPmessageisabletocontaincustomizedSOAPheaders.Thesearekey-valuepairswherethekeyisaqualifiedname(QName)andthevalueanormalStringvalue.

<header><elementname="http://www.consol.de/sayHelloh1:Operation"value="sayHello"/><elementname="http://www.consol.de/sayHelloh1:Request"value="HelloRequest"/></header>

ThekeyisdefinedasqualifiedQNamecharactersequencewhichhasamandatoryXMLnamespaceandaprefixalongwithaheadername.LastnotleastaSOAPheadercancontainwholeXMLfragmentvalues.ThenextexampleshowshowtosettheseXMLfragmentsasSOAPheaderinCitrus:

<header><data><![CDATA[<Userxmlns="http://www.consol.de/schemas/sayHello">

CitrusReferenceGuide

275Soap

Page 276: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<UserId>123456789</UserId><Handshake>S123456789</Handshake></User>]]></data></header>

YoucanalsouseexternalfileresourcestosetthisSOAPheaderXMLfragmentasshowninthislastexamplecode:

<header><resourcefile="classpath:request-soap-header.xml"/></header>

ThiscompletestheSOAPheaderpossibilitiesforsendingSOAPmessageswithCitrus.OfcourseyoucanalsousethesevariantsinSOAPmessageheadervalidation.YoudefineexpectedSOAPheaders,SOAPactionandXMLfragmentsandCitruswillmatchincomingrequesttothat.Justusecitrus_soap_actionheaderkeyinyourreceivingmessageactionandyouvalidatethisSOAPheaderaccordingly.

WhenvalidatingSOAPheaderXMLfragmentsyouneedtodefinethewholeXMLheaderfragmentasexpectedheaderdatalikethis:

<receiveendpoint="soapMessageEndpoint"><message><data><![CDATA[<ResponseMessagexmlns="http://citrusframework.org/schema"><resultCode>OK</resultCode></ResponseMessage>]]></data></message><header><data><![CDATA[<SOAP-ENV:Headerxmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><customHeaderxmlns="http://citrusframework.org/headerschema"><correlationId>$correlationId</correlationId><applicationId>$applicationId</applicationId><trackingId>$trackingId</trackingId><serviceId>$serviceId</serviceId><interfaceVersion>1.0</interfaceVersion><timestamp>@ignore@</timestamp></customHeader>

CitrusReferenceGuide

276Soap

Page 277: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</SOAP-ENV:Header>]]></data><elementname="citrus_soap_action"value="doResponse"/></header></receive>

AsyoucanseetheSOAPXMLheadervalidationcancombineheaderelementandXMLfragmentvalidation.ThisisalsolikelytobeusedwhendealingwithWS-Securitymessageheaders.

SOAPHTTPmimeheaders

BesidestheSOAPspecificheaderelementstheHTTPmimeheaders(e.g.Content-Type,Content-Length,Authorization)mightbecandidatesforvalidation,too.WhenusingHTTPastransportlayertheSOAPmessagemaydefinethosemimeheaders.Thetesterisabletosendandvalidatetheseheadersinsidethetestcase,althoughtheseHTTPheadersarelocatedoutsideoftheSOAPenvelope.LetusfirstofallspeakaboutvalidatingtheHTTPmimeheaders.Thisfeatureisnotenabledbydefault.WehaveenablethisinourSOAPserverconfiguration.

<citrus-ws:serverid="helloSoapServer"port="8080"auto-start="true"handle-mime-headers="true"resource-base="src/it/resources"/>

WiththisconfigurationCitruswillhandleallavailablemimeheadersandpassthosetothetestcasefornormalheadervalidation.

<ws:receiveendpoint="helloSoapServer"><message><payload><SoapMessageRequestxmlns="http://www.consol.de/schemas/sample.xsd"><Operation>Validatemimeheaders</Operation></SoapMessageRequest></payload></message><header><elementname="Content-Type"value="text/xml;charset=utf-8"/></header></ws:receive>

CitrusReferenceGuide

277Soap

Page 278: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ThevalidationoftheseHTTPmimeheadersisasusualnowthatwehaveenabledthemimeheaderhandlingintheSOAPserver.ThetransportHTTPheadersareavailableintheheaderjustlikethenormalSOAPheaderelementsdo.Soyoucanvalidatetheheadersasusual.

SomuchforreceivingandvalidatingHTTPmimemessageheaderswithSOAPcommunication.Nowwewanttosendspecialmimeheadersonclientside.Weoverwriteoraddmimeheaderstooursendingaction.Wemarksomeheaderswithfollowingprefix"citrushttp".ThistellstheSOAPclienttoaddtheseheaderstotheHTTPheadersectionoutsidetheSOAPenvelope.KeepinmindthatheaderelementswithoutthisprefixgorightintotheSOAPheadersectionbydefault.

<ws:sendendpoint="soapClient">[...]<header><elementname="citrus_http_operation"value="foo"/></header>[...]</ws:send>

ThelistingabovedefinesaHTTPmimeheaderoperation.TheheaderprefixcitrushttpiscutoffbeforetheheadergoesintotheHTTPheadersection.Withthisfeaturewecandecidewhereexactlyourheaderinformationislocatedinourresultingclientmessage.

SOAPEnvelopehandling

BydefaultCitruswillremovetheSOAPenvelopeinmessageconverter.FollowingfromthattheCitrustestcaseisindependentfromSOAPmessageformatsandisnotbotheredwithhandlingofSOAPenvelopeatall.ThisisgreatinmostcasesbutsometimesitmightbemandatorytoalsoseethewholeSOAPenvelopeinsidethetestcasereceiveaction.ThereforeyoucankeeptheSOAPenvelopeforincomingmessagesbyconfigurationontheSOAPserverside.

<citrus-ws:serverid="helloSoapServer"port="8080"auto-start="true"keep-soap-envelope="true"/>

WiththisconfigurationCitruswillhandleallavailablemimeheadersandpassthosetothetestcasefornormalheadervalidation.

CitrusReferenceGuide

278Soap

Page 279: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<ws:receiveendpoint="helloSoapServer"><message><payload><SOAP-ENV:Envelopexmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><SoapMessageRequestxmlns="http://www.consol.de/schemas/sample.xsd"><Operation>Validatemimeheaders</Operation></SoapMessageRequest></SOAP-ENV:Body></SOAP-ENV:Envelope></payload></message></ws:receive>

SonowyouareabletovalidatethewholeSOAPenvelopeasis.Thismightbeofinterestinveryspecialcases.AsmentionedbydefaulttheCitrusserverwillautomaticallyremovetheSOAPenvelopeandtranslatetheSOAPbodytothemessagepayloadforstraightforwardvalidationinsidethetestcases.

SOAPserverinterceptors

TheCitrusSOAPserversupportstheconceptofinterceptorsinordertoaddcustomlogictotherequest/responseprocessingsteps.Theinterceptorsneedtoimplementacommoninterface:org.springframework.ws.server.EndpointInterceptor.Weareabletocustomizetheinterceptorchainontheservercomponentasfollows:

<citrus-ws:serverid="secureSoapServer"port="8080"auto-start="true"interceptors="serverInterceptors"/>

<util:listid="serverInterceptors"><beanclass="com.consol.citrus.ws.interceptor.SoapMustUnderstandEndpointInterceptor"><propertyname="acceptedHeaders"><list><value>http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsdSecurity</list></property></bean><beanclass="com.consol.citrus.ws.interceptor.LoggingEndpointInterceptor"/><beanclass="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor"><propertyname="validationActions"value="TimestampUsernameToken"/><propertyname="validationCallbackHandler"><beanid="passwordCallbackHandler"class="org.springframework.ws.soap.security.wss4j.callback.SimplePasswordValidationCallbackHandler"<propertyname="usersMap">

CitrusReferenceGuide

279Soap

Page 280: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<map><entrykey="admin"value="secret"/></map></property></bean></property></bean></util:list>

ThecustominterceptorsareusedtoenableWsSecurityfeaturesonthesoapservercomponentviaWss4J.

NoteWhencustomizingtheinterceptorchainofthesoapservercomponentalldefaultinterceptors(likelogginginterceptors)arelost.Youcanseethatwehadtoaddthecom.consol.citrus.ws.interceptor.LoggingEndpointInterceptorexplicitlyinordertologrequest/responsemessagesfortheservercommunication.

SOAP1.2

BydefaultCitruscomponentsuseSOAP1.1version.FortunatelySOAP1.2issupportedsameway.AswealreadymentionedbeforetheCitrusSOAPcomponentsdouseaSOAPmessagefactoryforcreatingmessagesinSOAPformat.

<!--SOAP1.1MessageFactory--><beanid="soapMessageFactory"class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"<propertyname="soapVersion"><util:constantstatic-field="org.springframework.ws.soap.SoapVersion.SOAP_11"/></property></bean>

<!--SOAP1.2MessageFactory--><beanid="soap12MessageFactory"class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"<propertyname="soapVersion"><util:constantstatic-field="org.springframework.ws.soap.SoapVersion.SOAP_12"/></property></bean>

AsyoucanseetheSOAPmessagefactorycaneithercreateSOAP1.1orSOAP1.2messages.ThisishowCitruscancreatebothSOAP1.1andSOAP1.2messages.Ofcourseyoucanhavemultiplemessagefactoriesconfiguredinyourproject.JustsetthemessagefactoryonaWebServiceclientorservercomponentinordertodefinewhichversionshouldbeused.

CitrusReferenceGuide

280Soap

Page 281: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<citrus-ws:clientid="soap12Client"request-url="http://localhost:8080/echo"message-factory="soap12MessageFactory"timeout="1000"/>

<citrus-ws:serverid="soap12Server"port="8080"auto-start="true"root-parent-context="true"message-factory="soap12MessageFactory"/>

BydefaultCitruscomponentsdoconnectwithamessagefactorycalledmessageFactorynomatterwhatSOAPversionthisfactoryisusing.

SOAPfaults

SOAPfaultsdescribeafailedcommunicationinSOAPWebServicesworld.CitrusisabletosendandreceiveSOAPfaultmessages.OnserversideCitruscansimulateSOAPfaultswithfault-code,fault-reason,fault-actorandfault-detail.OnclientsideCitrusisabletohandleandvalidateSOAPfaultsinresponsemessages.ThenextsectiondescribeshowtodealwithSOAPfaultsinCitrus.

SendSOAPfaults

AsCitrussimulatesSOAPserverendpointsyoualsoneedtothinkaboutsendingaSOAPfaulttothecallingclient.IncaseCitrusreceivesaSOAPrequestasaserveryoucanrespondwithaproperSOAPfaultifnecessary.

Pleasekeepinmindthatweusethecitrus-wsextensionforsendingSOAPfaultsinourtestcase,asshowninthisverysimpleexample:

XMLDSL

<ws:send-faultendpoint="helloSoapServer"><ws:fault><ws:fault-code>http://www.citrusframework.org/faultscitrus:TEC-1000</ws:fault-code><ws:fault-string>Invalidrequest</ws:fault-string><ws:fault-actor>SERVER</ws:fault-actor><ws:fault-detail><![CDATA[<FaultDetailxmlns="http://www.consol.de/schemas/sayHello.xsd"><MessageId>$messageId</MessageId><CorrelationId>$correlationId</CorrelationId><ErrorCode>TEC-1000</ErrorCode>

CitrusReferenceGuide

281Soap

Page 282: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<Text>Invalidrequest</Text></FaultDetail>]]></ws:fault-detail></ws:fault><ws:header><ws:elementname="citrus_soap_action"value="sayHello"/></ws:header></ws:send-fault>

TheexamplegeneratesasimpleSOAPfaultthatissentbacktothecallingclient.Thefault-actorandthefault-detailelementsareoptional.SamewiththesoapactiondeclaredinthespecialCitrusheadercitrus_soap_action.Inthesampleabovethefault-detaildataisplacedinlineasXMLdata.Asanalternativetothatyoucanalsosetthefault-detailviaexternalfileresource.JustusethefileattributeasfaultdetailinsteadoftheinlineCDATAdefinition.

XMLDSL

<ws:send-faultendpoint="helloSoapServer"><ws:fault><ws:fault-code>http://www.citrusframework.org/faultscitrus:TEC-1000</ws:fault-code><ws:fault-string>Invalidrequest</ws:fault-string><ws:fault-actor>SERVER</ws:fault-actor><ws:fault-detailfile="classpath:myFaultDetail.xml"/></ws:fault><ws:header><ws:elementname="citrus_soap_action"value="sayHello"/></ws:header></ws:send-fault>

ThegeneratedSOAPfaultlookslikefollows:

HTTP/1.1500InternalServerErrorAccept:text/xml,text/html,image/gif,image/jpeg,*;q=.2,*/*;q=.2SOAPAction:"sayHello"Content-Type:text/xml;charset=utf-8Content-Length:680Server:Jetty(7.0.0.pre5)

<SOAP-ENV:Envelopexmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><SOAP-ENV:Fault>

CitrusReferenceGuide

282Soap

Page 283: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<faultcodexmlns:citrus="http://www.citrusframework.org/faults">citrus:TEC-1000</<faultstringxml:lang="en">Invalidrequest</faultstring><detail><FaultDetailxmlns="http://www.consol.de/schemas/sayHello.xsd"><MessageId>9277832563</MessageId><CorrelationId>4346806225</CorrelationId><ErrorCode>TEC-1000</ErrorCode><Text>Invalidrequest</Text></FaultDetail></detail></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>

ImportantNoticethatthesendactionusesaspecialXMLnamespace(ws:send).ThiswsnamespacebelongstotheCitrusWebServiceextensionandaddsSOAPspecificfeaturestothenormalsendaction.Whenyouusesuchwsextensionsyouneedtodefinetheadditionalnamespaceinyourtestcase.Thisisusuallydoneintheroot<spring:beans>elementwherewesimplydeclarethecitrus-wsspecificnamespacelikefollows.```xml

###ReceiveSOAPfaults

IncaseyoureceiveSOAPresponsemessagesasaclientendpointyoumayneedtohandleandvalidateSOAPfaultsinerrorsituations.CitruscanvalidateSOAPfaultswithfault-code,fault-actor,fault-stringandfault-detailvalues.

AsaclientwesendoutarequestandreceiveaSOAPfaultasresponse.BydefaulttheclientsendingactioninCitrusthrowsaspecificexceptionwhentheSOAPresponseisaSOAPfaultelement.Thisexceptioniscalled***SoapFaultClientException***comingfromtheSpringAPI.YouasatestercanassertthiskindofexceptioninatestcaseinordertoexpecttheSOAPerror.

**XMLDSL**

```xml<assertclass="org.springframework.ws.soap.client.SoapFaultClientException"><sendendpoint="soapClient"><message><payload><SoapFaultForcingRequestxmlns="http://www.consol.de/schemas/soap"><Message>Thisisinvalid</Message></SoapFaultForcingRequest></payload></message></send></assert>

CitrusReferenceGuide

283Soap

Page 284: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TheSOAPmessagesendingactionissurroundedbyasimpleassertaction.TheassertedexceptionclassistheSoapFaultClientExceptionthatwehavementionedbefore.Thismeansthatthetestexpectstheexceptiontobethrownduringthecommunication.Incasetheexceptionismissingthetestisfails.

SofarwehaveusedtheCitruscorecapabilitiesofassertinganexception.ThisbasicassertiontestactionisnotabletoofferdirectaccesstotheSOAPfault-codeandfault-stringvaluesforvalidation.ThebasicassertactionsimplyhasnoaccesstotheactualSOAPfaultelements.Fortunatelywecanusethecitrus-wsnamespaceagainwhichoffersaspecialassertactionimplementationespeciallydesignedforSOAPfaultsinthiscase.

XMLDSL

<ws:assert-faultfault-code="http://www.citrusframework.org/faultsTEC-1001"fault-string="Invalidrequest">fault-actor="SERVER"><ws:when><sendendpoint="soapClient"><message><payload><SoapFaultForcingRequestxmlns="http://www.consol.de/schemas/soap"><Message>Thisisinvalid</Message></SoapFaultForcingRequest></payload></message></send></ws:when></ws:assert-fault>

ThespecialassertactionoffersseveralattributestovalidatetheexpectedSOAPfault.Namelytheseare"fault-code","fault-string"and"fault-actor".Thefault-codeisdefinedasaQNamestringandismandatoryforthevalidation.Thefaultassertionalsosupportstestvariablereplacementasusual(e.g.fault-code="http://www.citrusframework.org/faults$myFaultCode").

ThetimeyouuseSOAPfaultvalidationyouneedtotellCitrushowtovalidatetheSOAPfaults.CitrusneedsaninstanceofaSoapFaultValitatorthatweneedtoaddtotheSpringapplicationcontext.BydefaultCitrusissearchingforabeanwiththeid'soapFaultValidator'.

<beanid="soapFaultValidator"class="com.consol.citrus.ws.validation.SimpleSoapAttachmentValidator"

CitrusReferenceGuide

284Soap

Page 285: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

CitrusoffersseveralreferenceimplementationsfortheseSOAPfaultvalidators.Theseare:

com.consol.citrus.ws.validation.SimpleSoapAttachmentValidatorcom.consol.citrus.ws.validation.SimpleSoapFaultValidatorcom.consol.citrus.ws.validation.XmlSoapFaultValidator

PleaseseetheAPIdocumentationfordetailsontheavailablereferenceimplementations.OfcourseyoucanalsodefineyourownSOAPvalidatorlogic(wouldbegreatifyoucouldshareyourideas!).Inthetestcaseyoucanexplicitlychoosethevalidatortouse:

XMLDSL

<ws:assert-faultfault-code="http://www.citrusframework.org/faultsTEC-1001"fault-string="Invalidrequest"fault-validator="mySpecialSoapFaultValidator">[...]</ws:assert-fault>

ImportantAnotherimportantthingtonoticewhenassertingSOAPfaultsisthefact,thatCitrusneedstohaveaSoapMessageFactoryavailableintheSpringapplicationcontext.IfyoudealwithSOAPmessagingingeneralyouwillalreadyhavesuchabeaninthecontext.

<beanid="messageFactory"class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>

ChooseoneofSpring'sreferenceimplementationsorsomeotherimplementationasSOAPmessagefactory.Citruswillsearchforabeanwithid'messageFactory'bydefault.IncaseyouhaveotherbeanswithdifferentidentifierspleasechoosethemessageFactoryinthetestcaseassertaction:

XMLDSL

<ws:assert-faultfault-code="http://www.citrusframework.org/faultsTEC-1001"fault-string="Invalidrequest"message-factory="mySpecialMessageFactory">[...]</ws:assert-fault>

CitrusReferenceGuide

285Soap

Page 286: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ImportantNoticethewsspecificnamespacethatbelongstotheCitrusWebServiceextensions.Asthews:assertactionusesSOAPspecificfeaturesweneedtorefertothecitrus-wsnamespace.Youcanfindthenamespacedeclarationintherootelementinyourtestcase.```xml

CitrusisalsoabletovalidateSOAPfaultdetails.Seethefollowingexampleforunderstandinghowtodoit:

**XMLDSL**

```xml<ws:assert-faultfault-code="http://www.citrusframework.org/faultsTEC-1001"fault-string="Invalidrequest"><ws:fault-detail><![CDATA[<FaultDetailxmlns="http://www.consol.de/schemas/soap"><ErrorCode>TEC-1000</ErrorCode><Text>Invalidrequest</Text></FaultDetail>]]></ws:fault-detail><ws:when><sendendpoint="soapClient"><message><payload><SoapFaultForcingRequestxmlns="http://www.consol.de/schemas/soap"><Message>Thisisinvalid</Message></SoapFaultForcingRequest></payload></message></send></ws:when></ws:assert-fault>

TheexpectedSOAPfaultdetailcontentissimplyaddedtothews:assertaction.TheSoapFaultValidatorimplementationdefinedintheSpringapplicationcontextisresponsibleforcheckingtheSOAPfaultdetailwithvalidationalgorithm.Thevalidatorimplementationchecksthedetailcontenttomeettheexpectedtemplate.CitrusprovidessomedefaultSoapFaultValidatorimplementations.SupportedalgorithmsarepureStringcomparison(com.consol.citrus.ws.validation.SimpleSoapFaultValidator)aswellasXMLtreewalk-through(com.consol.citrus.ws.validation.XmlSoapFaultValidator).

CitrusReferenceGuide

286Soap

Page 287: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

WhenusingtheXMLvalidationalgorithmyouhavethecompletepowerasknownfromnormalmessagevalidationinreceiveactions.Thisincludesschemavalidationorignoringelementsforinstance.Onthefault-detailelementyouareabletoaddsomevalidationsettingssuchasschema-validation=enabled/disabled,customschema-repositoryandsoon.

XMLDSL

<ws:assert-faultfault-code="http://www.citrusframework.org/faultsTEC-1001"fault-string="Invalidrequest"><ws:fault-detailschema-validation="false"><![CDATA[<FaultDetailxmlns="http://www.consol.de/schemas/soap"><ErrorCode>TEC-1000</ErrorCode><Text>Invalidrequest</Text></FaultDetail>]]></ws:fault-detail><ws:when><sendendpoint="soapClient">[...]</send></ws:when></ws:assert-fault>

PleaseseealsotheCitrusAPIdocumentationforavailablevalidatorimplementationsandvalidationalgorithms.

SofarwehaveusedassertactionwrapperinordertocatchSOAPfaultexceptionsandvalidatetheSOAPfaultcontent.NowwehaveanalternativewayofhandlingSOAPfaultsinCitrus.WithexceptionsthesendactionabortsandwedonothaveareceiveactionfortheSOAPfault.ThismightbeinadequateifweneedtovalidatetheSOAPmessagecontent(SOAPHeaderandSOAPBody)comingwiththeSOAPfault.Thereforethewebservicemessagesendercomponentoffersseveralfaultstrategyoptions.InthefollowingwediscussthepropagationofSOAPfaultasmessagestothereceiveactionaswewoulddowithnormalSOAPmessages.

<citrus-ws:clientid="soapClient"request-url="http://localhost:8090/test"fault-strategy="propagateError"/>

CitrusReferenceGuide

287Soap

Page 288: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

WehaveconfiguredafaultstrategypropagateErrorsothemessagesenderwillnotraiseclientexceptionsbutinformthereceiveactionwithSOAPfaultmessagecontents.Bydefaultthefaultstrategyraisesclientexceptions(fault-strategy=throwsException).

Sonowthatwedonotraiseexceptionswecanleaveouttheassertactionwrapperinourtest.InsteadwesimplyuseareceiveactionandvalidatetheSOAPfaultlikethis.

<sendendpoint="soapClient"><message><payload><SoapFaultForcingRequestxmlns="http://www.consol.de/schemas/sample.xsd"><Message>Thisisinvalid</Message></SoapFaultForcingRequest></payload></message></send>

<receiveendpoint="soapClient"timeout="5000"><message><payload><SOAP-ENV:Faultxmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><faultcodexmlns:CITRUS="http://citrus.org/soap">CITRUS:$soapFaultCode</faultcode<faultstringxml:lang="en">$soapFaultString</faultstring></SOAP-ENV:Fault></payload></message></receive>

SochoosethepreferredwayofhandlingSOAPfaultseitherbyassertingclientexceptionsorpropagatingfaultmessagestothereceiveactiononaSOAPclient.

MultipleSOAPfaultdetails

SOAPfaultmessagescanholdmultipleSOAPfaultdetailelements.IntheprevioussectionswehaveusedSOAPfaultdetailsinsendingandreceivingactionsassingleelement.InordertomeettheSOAPspecificationCitrusisalsoabletohandlemultipleSOAPfaultdetailelementsinamessage.Youjustusemultiplefault-detailelementsinyourtestactionlikethis:

<ws:send-faultendpoint="helloSoapServer"><ws:fault><ws:fault-code>http://www.citrusframework.org/faultscitrus:TEC-1000</ws:fault-code><ws:fault-string>Invalidrequest</ws:fault-string><ws:fault-actor>SERVER</ws:fault-actor>

CitrusReferenceGuide

288Soap

Page 289: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<ws:fault-detail><![CDATA[<FaultDetailxmlns="http://www.consol.de/schemas/sayHello.xsd"><MessageId>$messageId</MessageId><CorrelationId>$correlationId</CorrelationId><ErrorCode>TEC-1000</ErrorCode><Text>Invalidrequest</Text></FaultDetail>]]></ws:fault-detail><ws:fault-detail><![CDATA[<ErrorDetailxmlns="http://www.consol.de/schemas/sayHello.xsd"><ErrorCode>TEC-1000</ErrorCode></ErrorDetail>]]></ws:fault-detail></ws:fault><ws:header><ws:elementname="citrus_soap_action"value="sayHello"/></ws:header></ws:send-fault>

ThiswillresultinfollowingSOAPenvelopemessage:

HTTP/1.1500InternalServerErrorAccept:text/xml,text/html,image/gif,image/jpeg,*;q=.2,*/*;q=.2SOAPAction:"sayHello"Content-Type:text/xml;charset=utf-8Content-Length:680Server:Jetty(7.0.0.pre5)

<SOAP-ENV:Envelopexmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><SOAP-ENV:Fault><faultcodexmlns:citrus="http://www.citrusframework.org/faults">citrus:TEC-1000</<faultstringxml:lang="en">Invalidrequest</faultstring><detail><FaultDetailxmlns="http://www.consol.de/schemas/sayHello.xsd"><MessageId>9277832563</MessageId><CorrelationId>4346806225</CorrelationId><ErrorCode>TEC-1000</ErrorCode><Text>Invalidrequest</Text></FaultDetail><ErrorDetailxmlns="http://www.consol.de/schemas/sayHello.xsd"><ErrorCode>TEC-1000</ErrorCode></ErrorDetail></detail>

CitrusReferenceGuide

289Soap

Page 290: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>

OfcoursewecanalsoexpectseveralfaultdetailelementswhenreceivingaSOAPfault.

XMLDSL

<ws:assert-faultfault-code="http://www.citrusframework.org/faultsTEC-1001"fault-string="Invalidrequest"><ws:fault-detailschema-validation="false"><![CDATA[<FaultDetailxmlns="http://www.consol.de/schemas/soap"><ErrorCode>TEC-1000</ErrorCode><Text>Invalidrequest</Text></FaultDetail>]]></ws:fault-detail><ws:fault-detail><![CDATA[<ErrorDetailxmlns="http://www.consol.de/schemas/soap"><ErrorCode>TEC-1000</ErrorCode></ErrorDetail>]]></ws:fault-detail><ws:when><sendendpoint="soapClient">[...]</send></ws:when></ws:assert-fault>

Asyoucanseewecanindividuallyusevalidationsettingsforeachfaultdetail.Intheexampleabovewedisabledschemavalidationforthefirstfaultdetailelement.

SendHTTPerrorcodeswithSOAP

TheSOAPserverlogicinCitrusisabletosimulatepureHTTPerrorcodessuchas404"Notfound"or500"Internalservererror".ThegoodthingisthattheCitrusserverisabletoreceivearequestforpropervalidationinareceiveactionandthensimulateHTTPerrorsondemand.

CitrusReferenceGuide

290Soap

Page 291: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ThemechanismonHTTPerrorcodesimulationisnotdifferenttotheusualSOAPrequest/responsehandlinginCitrus.Wereceivetherequestasusualandweprovidearesponse.TheHTTPerrorsituationissimulatedaccordingtothespecialHTTPheadercitrus_http_statusintheCitrusSOAPresponsedefinition.Incasethisheaderissettoavalueotherthan200OKtheCitrusSOAPserversendsanemptySOAPresponsewithHTTPerrorstatuscodesetaccordingly.

<receiveendpoint="helloSoapServer"><message><payload><Messagexmlns="http://consol.de/schemas/sample.xsd"><Text>HelloSOAPserver</Text></Message></payload></message></receive>

<sendendpoint="helloSoapServer"><message><data></data></message><header><elementname="citrus_http_status_code"value="500"/></header></send>

TheSOAPresponsemustbeemptyandtheHTTPstatuscodeissettoavalueotherthan200,like500.ThisresultsinaHTTPerrorsenttothecallingclientwitherror500"Internalservererror".

SOAPattachmentsupport

CitrusisabletoaddattachmentstoaSOAPrequestonclientandserverside.AsusualyoucanvalidatetheSOAPattachmentcontentonareceivedSOAPmessage.ThenextchaptersdescribehowtohandleSOAPattachmentsinCitrus.

SendSOAPattachments

AsclientCitrusisabletoaddattachmentstotheSOAPmessage.Ithinkitisbesttogostraightintoanexampleinordertounderstandhowitworks.

<ws:sendendpoint="soapClient"><message>

CitrusReferenceGuide

291Soap

Page 292: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<payload><SoapMessageWithAttachmentxmlns="http://consol.de/schemas/sample.xsd"><Operation>Readtheattachment</Operation></SoapMessageWithAttachment></payload></message><ws:attachmentcontent-id="MySoapAttachment"content-type="text/plain"><ws:resourcefile="classpath:com/consol/citrus/ws/soapAttachment.txt"/></ws:attachment></ws:send>

NoteInthepreviouschaptersyoumayhavealreadynoticedthecitrus-wsnamespacethatstandsfortheSOAPextensionsinCitrus.Pleaseincludethecitrus-wsnamespaceinyourtestcaseasdescribedearlierinthischaptersoyoucanusetheattachmentsupport.

ThespecialsendactionoftheSOAPextensionnamespaceisawareofSOAPattachments.Theattachmentcontentusuallyconsistsofacontent-idacontent-typeandtheactualcontentasplaintextorbinarycontent.InsidethetestcaseyoucanuseexternalfileresourcesorinlineCDATAsectionsfortheattachmentcontent.AsyouarefamiliarwithCitrusyoumayknowthisalreadyfromotheractions.

CitruswillconstructaSOAPmessagewiththeSOAPattachment.Currentlyonlyoneattachmentpermessageissupported.

ReceiveSOAPattachments

WhenCitruscallsSOAPWebServicesasaclientwemayreceiveSOAPresponseswithattachments.ThetestercanvalidatethosereceivedSOAPmessageswithattachmentcontentquiteeasy.Asusualletushavealookatanexamplefirst.

<ws:receiveendpoint="soapClient"><message><payload><SoapMessageWithAttachmentRequestxmlns="http://consol.de/schemas/sample.xsd"><Operation>Readtheattachment</Operation></SoapMessageWithAttachmentRequest></payload></message><ws:attachmentcontent-id="MySoapAttachment"content-type="text/plain"validator="mySoapAttachmentValidator"><ws:resourcefile="classpath:com/consol/citrus/ws/soapAttachment.txt"/></ws:attachment></ws:receive>

CitrusReferenceGuide

292Soap

Page 293: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

AgainweusetheCitrusSOAPextensionnamespacewiththespecificreceiveactionthatisawareofSOAPattachmentvalidation.Thetestercanvalidatethecontent-id,thecontent-typeandtheattachmentcontent.InsteadofusingtheexternalfileresourceyoucouldalsodefineanexpectedattachmenttemplatedirectlyinthetestcaseasinlineCDATAsection.

NoteThews:attachmentelementspecifiesavalidatorinstance.Thisvalidatordetermineshowtovalidatetheattachmentcontent.SOAPattachmentsarenotlimitedtoXMLcontent.Plaintextcontentandbinarycontentispossible,too.SoeachSOAPattachmentvalidatingactioncanuseadifferentSoapAttachmentValidatorinstancewhichisresponsibleforvalidatingandcomparingreceivedattachmentstoexpectedtemplateattachments.IntheCitrusconfigurationthevalidatorissetasnormalSpringbeanwiththerespectiveidentifier.

<beanid="soapAttachmentValidator"class="com.consol.citrus.ws.validation.SimpleSoapAttachmentValidator"<beanid="mySoapAttachmentValidator"class="com.company.ws.validation.MySoapAttachmentValidator"

YoucandefineseveralvalidatorinstancesintheCitrusconfiguration.Thevalidatorwiththegeneralid"soapAttachmentValidator"isthedefaultvalidatorforallactionsthatdonotexplicitlysetavalidatorinstance.Citrusoffersasetofreferencevalidatorimplementations.TheSimpleSoapAttachmentValidatorwilluseasimpleplaintextcomparison.Ofcourseyouareabletoaddindividualvalidatorimplementations,too.

SOAPMTOMsupport

MTOM(MessageTransmissionOptimizationMechanism)enablesyoutosendandreceivelargeSOAPmessagecontentusingstreameddatahandlers.Thisoptimizestheresourceallocationonserverandclientsidewherenotalldataisloadedintomemorywhenmarshalling/unmarshallingthemessagepayloaddata.IndetailMTOMenabledmessagesdohaveaXOPpackageinsidethemessagepayloadreplacingtheactuallargecontentdata.Thecontentisthenstreamedaasseparateattachment.Serverandclientcanoperatewithadatahandlerprovidingaccesstothestreamedcontent.ThisisveryhelpfulwhenusinglargebinarycontentinsideaSOAPmessageforinstance.

CitrusisabletobothsendandreceiveMTOMenabledSOAPmessagesonclientandserver.Justusethemtom-enabledflagwhensendingaSOAPmessage:

<ws:sendendpoint="soapMtomClient"mtom-enabled="true"><message>

CitrusReferenceGuide

293Soap

Page 294: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<data><![CDATA[<image:addImagexmlns:image="http://www.citrusframework.org/imageService/"><image>cid:IMAGE</image></image:addImage>]]></data></message><ws:attachmentcontent-id="IMAGE"content-type="application/octet-stream"><ws:resourcefile="classpath:com/consol/citrus/hugeImageData.png"/></ws:attachment></ws:send>

AsyoucanseetheexampleabovesendsaSOAPmessagethatcontainsalargebinaryimagecontent.Theactualbinaryimagedataisreferencedwithacontentidmarkercid:IMAGEinsidethemessagepayload.Theactualimagecontentisaddedasattachmentwithaseparatefileresource.Importantisherethecontent-idwhichmatchestheidmarkerintheSOAPmessagepayload(IMAGE).

CitrusbuildsaproperSOAPMTOMenabledmessageautomaticallyaddingtheXOPpackageinsidethemessage.ThebinarydataissentasseparateSOAPattachmentaccordingly.TheresultingSOAPmessagelookslikethis:

<SOAP-ENV:Envelopexmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header></SOAP-ENV:Header><SOAP-ENV:Body><image:addImagexmlns:image="http://www.citrusframework.org/imageService/"><image><xop:Includexmlns:xop="http://www.w3.org/2004/08/xop/include"href="cid:IMAGE"/></image:addImage></SOAP-ENV:Body></SOAP-ENV:Envelope>

OntheserversideCitrusisalsoabletohandleMTOMenabledSOAPmessages.InaserverreceiveactionyoucanspecifytheMTOMSOAPattachmentcontentasfollows.

<ws:receiveendpoint="soapMtomServer"mtom-enabled="true"><messageschema-validation="false"><data><![CDATA[<image:addImagexmlns:image="http://www.citrusframework.org/imageService/"><image><xop:Includexmlns:xop="http://www.w3.org/2004/08/xop/include"href="cid:IMAGE"/></image></image:addImage>]]></data></message>

CitrusReferenceGuide

294Soap

Page 295: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<ws:attachmentcontent-id="IMAGE"content-type="application/octet-stream"><ws:resourcefile="classpath:com/consol/citrus/hugeImageData.png"/></ws:attachment></ws:receive>

WedefinetheMTOMattachmentcontentasseparateSOAPattachment.Thecontent-idisreferencedsomewhereintheSOAPmessagepayloaddata.AtruntimeCitruswilladdtheXOPpackagedefinitionautomaticallyandperformvalidationonthemessageanditsstreamedMTOMattachmentdata.

NextthingthatwehavetotalkaboutisinlineMTOMdata.Thismeansthatthecontentshouldbeaddedaseitherbase64BinaryorhexBinaryencodedStringdatadirectlytothemessagecontent.Seethefollowingexamplethatusesthemtom-inlinesetting:

<ws:sendendpoint="soapMtomClient"mtom-enabled="true"><message><data><![CDATA[<image:addImagexmlns:image="http://www.citrusframework.org/imageService/"><image>cid:IMAGE</image><icon>cid:ICON</icon></image:addImage>]]></data></message><ws:attachmentcontent-id="IMAGE"content-type="application/octet-stream"mtom-inline="true"encoding-type="base64Binary"><ws:resourcefile="classpath:com/consol/citrus/image.png"/></ws:attachment><ws:attachmentcontent-id="ICON"content-type="application/octet-stream"mtom-inline="true"encoding-type="hexBinary"><ws:resourcefile="classpath:com/consol/citrus/icon.ico"/></ws:attachment></ws:send>

ThelistingabovedefinestwoinlineMTOMattachments.Thefirstattachmentcid:IMAGEusestheencodingtypebase64Binarywhichisthedefault.Thesecondattachmentcid:ICONuseshexBinaryencoding.Bothattachmentsareaddedasinlinedatabeforethemessageissent.ThefinalSOAPmessagelookslikefollows:

<SOAP-ENV:Envelopexmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header></SOAP-ENV:Header><SOAP-ENV:Body><image:addImagexmlns:image="http://www.citrusframework.org/imageService/"><image>VGhpcyBpcyBhIGJpbmFyeSBpbWFnZSBhdHRhY2htZW50IQpWYXJpYWJsZXMgJXt0ZXN0fSBzaG91bGQgbm90IGJlIHJlcGxhY2VkIQ==

CitrusReferenceGuide

295Soap

Page 296: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<icon>5468697320697320612062696E6172792069636F6E206174746163686D656E74210A5661726961626C657320257B746573747D2073686F756C64206E6F74206265207265706C6163656421</image:addImage></SOAP-ENV:Body></SOAP-ENV:Envelope>

Theimagecontentisabase64BinaryStringandtheiconaheyBinaryString.OfcoursethismechanismalsoissupportedinreceiveactionsontheserversidewheretheexpectedmessagecontentisaddedalsinlineMTOMdatabeforevalidationtakesplace.

SOAPclientbasicauthentication

AsaSOAPclientyoumayhavetousebasicauthenticationinordertoaccessaserverresource.BasicauthenticationviaHTTPstandsforusername/passwordauthenticationwherethecredentialsaretransmittedintheHTTPrequestheadersectionasbase64encodedentry.AsCitrususestheSpringWebServicestackwecanusethebasicauthenticationsupportthere.WesettheusercredentialsontheHttpClientmessagesenderwhichisusedinsidetheSpringWebServiceTemplate.

CitrusprovidesacomfortablewaytosettheHTTPmessagesenderwithbasicauthenticationcredentialsontheWebServiceTemplate.Justseethefollowingexampleandlearnhowtodothat.

<citrus-ws:clientid="soapClient"request-url="http://localhost:8090/test"message-sender="basicAuthClient"/>

<beanid="basicAuthClient"class="org.springframework.ws.transport.http.HttpComponentsMessageSender"<propertyname="authScope"><beanclass="org.apache.http.auth.AuthScope"><constructor-argvalue="localhost"/><constructor-argvalue="8090"/><constructor-argvalue=""/><constructor-argvalue="basic"/></bean></property><propertyname="credentials"><beanclass="org.apache.http.auth.UsernamePasswordCredentials"><constructor-argvalue="someUsername"/><constructor-argvalue="somePassword"/></bean></property></bean>

CitrusReferenceGuide

296Soap

Page 297: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TheaboveconfigurationresultsinSOAPrequestswithauthenticationheadersproperlysetforbasicauthentication.ThespecialmessagesendertakescareonaddingtheproperbasicauthenticationheadertoeachrequestthatissentwiththisCitrusmessagesender.Bydefaultpreemtiveauthenticationisused.Themessagesenderonlysendsasinglerequesttotheserverwithallauthenticationinformationsetinthemessageheader.Therequestwhichdeterminestheauthenticationschemeontheserverisskipped.ThisiswhyyouhavetoaddsomeauthscopesoCitruscansetupanauthenticationcachewithintheHTTPcontextinordertohavepreemtiveauthentication.

TipYoucanalsoskipthemessagesenderconfigurationandsettheAuthorizationheaderoneachrequestinyoursendactiondefinitiononyourown.BeawareofsettingtheheaderasHTTPmimeheaderusingthecorrectprefixandtakecareonusingthecorrectbasicauthenticationwithbase64encodingfortheusername:passwordphrase.

<header><elementname="citrus_http_Authorization"value="Basicc29tZVVzZXJuYW1lOnNvbWVQYXNzd29yZA=="</header>

Forbase64encodingyoucanalsouseaCitrusfunction,seefunctions-encode-base64

SOAPserverbasicauthentication

WhenprovidingSOAPWebServiceserverfunctionalityCitruscanalsosetbasicauthenticationsoallclientsneedtoauthenticateproperlywhenaccessingtheserverresource.

<citrus-ws:serverid="simpleSoapServer"port="8080"auto-start="true"resource-base="src/it/resources"security-handler="basicSecurityHandler"/>

<beanid="securityHandler"class="com.consol.citrus.ws.security.SecurityHandlerFactory"><propertyname="users"><list><beanclass="com.consol.citrus.ws.security.User"><propertyname="name"value="citrus"/><propertyname="password"value="secret"/><propertyname="roles"value="CitrusRole"/></bean></list></property><propertyname="constraints">

CitrusReferenceGuide

297Soap

Page 298: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<map><entrykey="/foo/*"><beanclass="com.consol.citrus.ws.security.BasicAuthConstraint"><constructor-argvalue="CitrusRole"/></bean></entry></map></property></bean>

Wehavesetasecurityhandlerontheserverwebcontainerwithaconstraintonallresourceswith/foo/*.Followingfromthattheserverrequiresbasicauthenticationfortheseresources.Thegrantedusersandrolesarespecifiedwithinthesecurityhandlerbeandefinition.ConnectingclientshavetosetthebasicauthHTTPheaderproperlyusingthecorrectuserandroleforaccessingtheCitrusservernow.

Youcancustomizethesecurityhandlerforyourveryspecificneeds(e.g.loadusersandroleswithJDBCfromadatabase).Justhavealookatthecodebaseandinspectthesettingsandpropertiesofferedbythesecurityhandlerinterface.

TipThismechanismisnotrestrictedtobasicauthenticationonly.Withothersettingsyoucanalsosetupdigestorform-basedauthenticationconstraintsveryeasy.

WS-Addressingsupport

ThewebservicestackoffersalotofdifferenttechnologiesandstandardswithinthecontextofSOAPWebServices.WespeakofWS-*specificationsinparticular.Oneofthesespecificationsdealswithaddressing.OnclientsideyoumayaddwsaheaderinformationtotherequestinordertogivetheserverinstructionshowtodealwithSOAPfaultsforinstance.

InCitrusWebServiceclientyoucanaddthoseheaderinformationusingthecommonconfigurationlikethis:

<citrus-ws:clientid="soapClient"request-url="http://localhost:8090/test"message-converter="wsAddressingMessageConverter"/>

<beanid="wsAddressingMessageConverter"class="com.consol.citrus.ws.message.converter.WsAddressingMessageConverter"<constructor-arg><beanid="wsAddressing200408"class="com.consol.citrus.ws.addressing.WsAddressingHeaders"<propertyname="version"value="VERSION200408"/><propertyname="action"value="http://citrus.sample/sayHello"/><propertyname="to"value="http://citrus.sample/server"/>

CitrusReferenceGuide

298Soap

Page 299: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<propertyname="from"><beanclass="org.springframework.ws.soap.addressing.core.EndpointReference"><constructor-argvalue="http://citrus.sample/client"/></bean></property><propertyname="replyTo"><beanclass="org.springframework.ws.soap.addressing.core.EndpointReference"><constructor-argvalue="http://citrus.sample/client"/></bean></property><propertyname="faultTo"><beanclass="org.springframework.ws.soap.addressing.core.EndpointReference"><constructor-argvalue="http://citrus.sample/fault/resolver"/></bean></property></bean></constructor-arg></bean>

TheWsAddressingheadervalueswillbeusedforallrequestmessagesthataresentwiththesoapclientcomponentsoapClient.YoucanoverwritetheWsAddressingheaderineachsendtestactioninyourtestthough.JustsetthespecialWsAddressingmessageheaderonyourrequest.Youcanusethefollowingmessageheadernamesinordertooverwritethedefaultaddressingheadersspecifiedinthemessageconverterconfiguration(alsoseetheclasscom.consol.citrus.ws.addressing.WsAddressingMessageHeaders).

citrus_soap_ws_addressing_messageIdaddressingmessageidasURIcitrus_soap_ws_addressing_fromaddressingfromendpointreferenceasURIcitrus_soap_ws_addressing_toaddressingtoURIcitrus_soap_ws_addressing_actionaddressingactionURIcitrus_soap_ws_addressing_replyToaddressingreplytoendpointreferenceasURIcitrus_soap_ws_addressing_faultToaddressingfaulttoendpointreferenceasURI

WhenusingthismessageheadersyouareabletoexplicitlyoverwritetheWsAddressingheaders.Testvariablesaresupportedofcoursewhenspecifyingthevalues.MostofthevaluesareparsedtoaURIvalueattheendsopleasemakesuretousecorrectURIStringrepresentations.

NoteTheWS-Addressingspecificationknowsseveralversions.Supportedversionare:

VERSION10(WS-Addressing1.0May2006)

CitrusReferenceGuide

299Soap

Page 300: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

VERSION200408(August2004editionoftheWS-Addressingspecification)

TheaddressingheadersfindaplaceintheSOAPmessageheaderwithrespectivenamespacesandvalues.ApossibleSOAPrequestwithWSaddressingheaderslookslikefollows:

<SOAP-ENV:Envelopexmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Headerxmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"><wsa:ToSOAP-ENV:mustUnderstand="1">http://citrus.sample/server</wsa:To><wsa:From><wsa:Address>http://citrus.sample/client</wsa:Address></wsa:From><wsa:ReplyTo><wsa:Address>http://citrus.sample/client</wsa:Address></wsa:ReplyTo><wsa:FaultTo><wsa:Address>http://citrus.sample/fault/resolver</wsa:Address></wsa:FaultTo><wsa:Action>http://citrus.sample/sayHello</wsa:Action><wsa:MessageID>urn:uuid:4c4d8af2-b402-4bc0-a2e3-ad33b910e394</wsa:MessageID></SOAP-ENV:Header><SOAP-ENV:Body><cit:HelloRequestxmlns:cit="http://citrus/sample/sayHello"><cit:Text>HelloCitrus!</cit:Text></cit:HelloRequest></SOAP-ENV:Body></SOAP-ENV:Envelope>

ImportantBydefaultwhennotsetexplicitlyonthemessageheaderstheWsAddressingmessageidpropertyisautomaticallygeneratedforeachrequest.YoucansetthemessageidgenerationstrategyintheSpringapplicationcontextmessageconverterconfiguration:

<beanid="wsAddressingMessageConverter"class="com.consol.citrus.ws.message.converter.WsAddressingMessageConverter"<propertyname="messageIdStrategy"><beanclass="org.springframework.ws.soap.addressing.messageid.UuidMessageIdStrategy"/></property></bean>

BydefaultthestrategywillcreateanewJavaUUIDforeachrequest.Thestrategyalsousesacommonresourcenameprefixurn:uuid:.Youcanoverwritethemessageidanytimeforeachrequestexplicitlybysettingthemessageheadercitrus_soap_ws_addressing_messageIdwitharespectivevalueonthemessageinyourtest.

CitrusReferenceGuide

300Soap

Page 301: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

SOAPclientforkmode

SOAPoverHTTPusessynchronouscommunicationbynature.ThismeansthatsendingaSOAPmessageinCitrusoverHTTPwillautomaticallyblockfurthertestactionsuntilthesynchronousHTTPresponsehasbeenreceived.Intestcasesthissynchronousblockingmightcauseproblemsforseveralreasons.AsimplereasonwouldbethatyouneedtodofurthertestactionsinparalleltothesynchronousHTTPSOAPcommunication(e.g.simulateanotherbackendsysteminthetestcase).

YoucanseparatetheSOAPsendactionfromtherestofthetestcasebyusingthe"fork"mode.TheSOAPclientwillautomaticallyopenanewJavaThreadforthesynchronouscommunicationandthetestisabletocontinuewithexecutionalthoughthesynchronousHTTPSOAPresponsehasnotarrivedyet.

<ws:sendendpoint="soapClient"fork="true"><message><payload><SoapRequestxmlns="http://www.consol.de/schemas/sample.xsd"><Operation>Readtheattachment</Operation></SoapRequest></payload></message></ws:send>

Withthe"fork"modeenabledthetestcontinueswithexecutionwhilethesendingactionwaitsforthesynchronousresponseinaseparateJavaThread.Youcouldreachthesamebehaviourwithacomplex/containerconstruct,butforkingthesendactionismuchmorestraightforward.

ImportantItishighlyrecommendedtouseaproper"timeout"settingontheSOAPreceiveactionwhenusingforkmode.Theforkedsendoperationmighttakesometimeandthecorrespondingreceiveactionmightrunintofailureastheresponsewashasnotbeenreceivedyet.Theresultwouldbeabrokentestbecauseofthemissingresponsemessage.Aproper"timeout"settingforthereceiveactionsolvesthisproblemastheactionwaitsforthistimeperiodandoccasionallyrepeatedlyasksfortheSOAPresponsemessage.Thefollowinglistingsetsthereceivetimeoutto10seconds,sotheactionwaitsfortheforkedsendactiontodelivertheSOAPresponseintime.

<ws:receiveendpoint="soapClient"timeout="10000"><message><payload><SoapResponsexmlns="http://www.consol.de/schemas/sample.xsd">

CitrusReferenceGuide

301Soap

Page 302: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<Operation>Didsomething</Operation><Success>true</Success></SoapResponse></payload></message></ws:receive>

SOAPservletcontextcustomization

ForhighlycustomizedSOAPservercomponentsinCitrusyoucandefineafullservletcontextconfigurationfile.HereyouhavethefullpowertoaddSpringendpointmappingsandcustomendpointimplementations.Youcansetthecustomservletcontextasexternalfileresourceontheservercomponent:

<citrus-ws:clientid="soapClient"context-config-location="classpath:citrus-ws-servlet.xml"message-factory="soap11MessageFactory"/>

Nowletushaveacloserlookatthecontext-config-locationattribute.ThisconfigurationdefinestheSpringapplicationcontextfileforendpoints,requestmappingsandotherSpringWSspecificinformation.PleaseseetheofficialSpringWSdocumentationfordetailsonthisSpringbasedconfiguration.Youcanalsojustcopythefollowingexampleapplicationcontextwhichshouldworkforyouingeneral.

<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd">

<beanid="loggingInterceptor"class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor"><description>Thisinterceptorlogsthemessagepayload.</description></bean>

<beanid="helloServicePayloadMapping"class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping"><propertyname="mappings"><props><propkey="http://www.consol.de/schemas/sayHelloHelloRequest">helloServiceEndpoint</prop>

CitrusReferenceGuide

302Soap

Page 303: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</props></property><propertyname="interceptors"><list><refbean="loggingInterceptor"/></list></property></bean>

<beanid="helloServiceEndpoint"class="com.consol.citrus.ws.server.WebServiceEndpoint"><propertyname="endpointAdapter"ref="staticResponseEndpointAdapter"/></bean>

<citrus:static-response-adapterid="staticResponseEndpointAdapter"><citrus:payload><![CDATA[<HelloResponsexmlns="http://www.consol.de/schemas/sayHello"><MessageId>123456789</MessageId><CorrelationId>CORR123456789</CorrelationId><User>WebServer</User><Text>HelloUser</Text></HelloResponse>]]></citrus:payload><citrus:header><citrus:elementname="http://www.consol.de/schemas/samples/sayHello.xsdns0:Operation"value="sayHelloResponse"/><citrus:elementname="http://www.consol.de/schemas/samples/sayHello.xsdns0:Request"value="HelloRequest"/><citrus:elementname="citrus_soap_action"value="sayHello"/></citrus:header></citrus:static-response-adapter></beans>

TheprogramlistingabovedescribesanormalSpringWSrequestmappingwithendpointconfigurations.Themappingisresponsibletoforwardincomingrequeststotheendpointwhichwillhandletherequestandprovideaproperresponsemessage.Firstofallweaddalogginginterceptortothecontextsoallincomingrequestsgetloggedtotheconsolefirst.Thenweuseapayloadmapping(PayloadRootQNameEndpointMapping)inordertomapallincoming'HelloRequest'SOAPmessagestothe'helloServiceEndpoint'.EndpointsareofessentialnatureinCitrusSOAPWebServicesimplementation.Theyareresponsibleforprocessingarequestinordertoprovideaproperresponsemessagethatissentbacktothecallingclient.Citrususestheendpointincombinationwithamessageendpointadapterimplementation.

CitrusReferenceGuide

303Soap

Page 304: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Theendpointworkstogetherwiththemessageendpointadapterthatisresponsibleforprovidingaresponsemessagefortheclient.ThevariousmessageendpointadapterimplementationsinCitruswerealreadydiscussedinendpoint-adapter.

Inthisexamplethe'helloServiceEndpoint'usesthe'static-response-adapter'whichisalwaysreturningastaticresponsemessage.Inmostcasesstaticresponseswillnotfitthetestscenarioandyouwillhavetorespondmoredynamically.

RegardlessofwhichmessageendpointadaptersetupyouareusinginyourtestcasetheendpointtransformstheresponseintoaproperSOAPmessage.Youcanaddasmanyrequestmappingsandendpointsasyouwanttotheservercontextconfiguration.SoyouareabletohandledifferentrequesttypeswithonesingleJettyserverinstance.

That'sitforconnectingwithSOAPWebServices!WesawhowtosendandreceiveSOAPmessageswithJettyandSpringWebServices.HavealookatthesamplescomingwithyourCitrusarchiveinordertolearnmoreabouttheSOAPmessagehandling.

CitrusReferenceGuide

304Soap

Page 305: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

FTPsupportCitrusisabletostartalittleftpserveracceptingincomingclientrequests.AlsoCitrusisabletocallFTPcommandsasaclient.ThenextsectionsdealwithFTPconnectivity.

NoteTheFTPcomponentsinCitrusarekeptinaseparateMavenmodule.SoyoushouldaddthemoduleasMavendependencytoyourprojectaccordingly.

<dependency><groupId>com.consol.citrus</groupId><artifactId>citrus-ftp</artifactId><version>2.7.1</version></dependency>

AsCitrusprovidesacustomizedFTPconfigurationschemafortheSpringapplicationcontextconfigurationfileswehavetoaddnametothetoplevelbeanselement.Simplyincludetheftp-confignamespaceintheconfigurationXMLfilesasfollows.

<beansxmlns="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-ftp="http://www.citrusframework.org/schema/ftp/config"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/confighttp://www.citrusframework.org/schema/config/citrus-config.xsdhttp://www.citrusframework.org/schema/http/confighttp://www.citrusframework.org/schema/ftp/config/citrus-ftp-config.xsd">

[...]

</beans>

NowwearereadytousethecustomizedCitrusFTPconfigurationelementswiththecitrus-ftpnamespaceprefix.

FTPclient

CitrusReferenceGuide

305Ftp

Page 306: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

WewanttouseCitrusfoconnecttodomeFTPserverasaclientsendingcommandssuchascreatingadirectoryorlistingallfiles.CitrusoffersaclientcomponentdoingexactlythisFTPclientconnection.

<citrus-ftp:clientid="ftpClient"host="localhost"port="22222"username="admin"password="admin"timeout="10000"/>

TheconfigurationabovedescribesaCitrusftpclientconnectedtoaftpserverwithftp://localhost:22222.Forauthenticationusernameandpasswordaredefinedaswellastheglobalconnectiontimeout.Theclientwillautomaticallysendusernameandpasswordforproperauthenticationtotheserverwhenopeninganewconnection.

Inatestcaseyouarenowabletousetheclienttopushcommandstotheserver.

<sendendpoint="ftpClient"fork="true"><message><data></data></message><header><elementname="citrus_ftp_command"value="PWD"/><elementname="citrus_ftp_arguments"value="test"/></header></send>

<receiveendpoint="ftpClient"><messagetype="plaintext"><data>PWD</data></message><header><elementname="citrus_ftp_command"value="PWD"/><elementname="citrus_ftp_arguments"value="test"/><elementname="citrus_ftp_reply_code"value="257"/><elementname="citrus_ftp_reply_string"value="@contains('iscurrentdirectory')@"/></header></receive>

Asyoucanseemostoftheftpcommunicationparametersarespecifiedasspecialheaderelementsinthemessage.CitrusautomaticallyconvertsthoseinformationtoproperFTPcommandsandresponsemessages.

FTPserver

CitrusReferenceGuide

306Ftp

Page 307: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

NowthatweareabletoaccessFTPasaclientwemightalsowanttosimulatetheserverside.ThereforeCitrusoffersaservercomponentthatislisteningonaportforincomingFTPconnections.Theserverhasadefaulthomedirectoryonthelocalfilesystemspecified.Butyoucanalsodefinehomedirectoriesperuser.Fornowletushavealookattheserverconfigurationcomponent:

<citrus-ftp:serverid="ftpServer">port="22222"auto-start="true"user-manager-properties="classpath:ftp.server.properties"/>

Theftpserverconfigurationisquitesimple.Theserverstartsautomaticallyandbindstoaport.Theuserconfigurationisreadfromauser-manager-propertyfile.Letushavealookatthecontentofthisusermanagementfile:

#Passwordis"admin"ftpserver.user.admin.userpassword=21232F297A57A5A743894A0E4A801FC3ftpserver.user.admin.homedirectory=target/ftp/user/adminftpserver.user.admin.enableflag=trueftpserver.user.admin.writepermission=trueftpserver.user.admin.maxloginnumber=0ftpserver.user.admin.maxloginperip=0ftpserver.user.admin.idletime=0ftpserver.user.admin.uploadrate=0ftpserver.user.admin.downloadrate=0

ftpserver.user.anonymous.userpassword=ftpserver.user.anonymous.homedirectory=target/ftp/user/anonymousftpserver.user.anonymous.enableflag=trueftpserver.user.anonymous.writepermission=falseftpserver.user.anonymous.maxloginnumber=20ftpserver.user.anonymous.maxloginperip=2ftpserver.user.anonymous.idletime=300ftpserver.user.anonymous.uploadrate=4800ftpserver.user.anonymous.downloadrate=4800

Asyoucanseeyouareabletodefineasmanyuserfortheftpserverasyoulike.Usernameandpassworddefinetheauthenticationontheserver.Inadditiontothatyouhaveplentyofconfigurationpossibilitiesperuser.CitrususestheApacheftpserverimplementation.SoformoredetailsonconfigurationcapabilitiespleaseconsulttheofficialApacheftpserverdocumentation.

CitrusReferenceGuide

307Ftp

Page 308: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Nowwewouldliketousetheserverinatestcase.Veryeasyyoujusthavetodefineareceivemessageactionwithinyourtestcasethatusestheserveridasendpointreference:

<echo><message>ReceiveuserloginonFTPserver</message></echo>

<receiveendpoint="ftpServer"><messagetype="plaintext"><data>USER</data></message><header><elementname="citrus_ftp_command"value="USER"/><elementname="citrus_ftp_arguments"value="admin"/></header></receive>

<sendendpoint="ftpServer"><messagetype="plaintext"><data>OK</data></message></send>

<echo><message>ReceiveuserpasswordonFTPserver</message></echo>

<receiveendpoint="ftpServer"><messagetype="plaintext"><data>PASS</data></message><header><elementname="citrus_ftp_command"value="PASS"/><elementname="citrus_ftp_arguments"value="admin"/></header></receive>

<sendendpoint="ftpServer"><messagetype="plaintext""><data>OK</data></message></send>

Thelistingaboveshowstwoincomingcommandsrepresentingauserlogin.Weindicatewithresendactionsthatwewouldlinktheservertorespondwithpositivefeedbackandtoacceptthelogin.Aswehaveafullyqualifiedftpserverrunningtheclientcanalso

CitrusReferenceGuide

308Ftp

Page 309: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

pushfilesreaddirectoriesandmore.Allincomingcommandscanbevalidatedinsideatestcase.

CitrusReferenceGuide

309Ftp

Page 310: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

MessagechannelsupportMessagechannelsrepresenttheinmemorymessagingsolutioninCitrus.Producerandconsumercomponentsarelinkedviachannelsexchangingmessagesinmemory.AsthistransportmechanismcomesfromSpringIntegrationAPI(http://www.springsource.org/spring-integration)andCitrusitselfusesalotofSpringAPIs,especiallythosefromSpringIntegrationyouareabletoconnecttoallSpringmessagingadaptersviatheseinmemorychannels.

CitrusoffersachannelcomponentsthatcanbeusedbothbyCitrusandSpringIntegration.TheconclusionisthatCitrussupportsthesendingandreceivingofmessagesbothtoandfromSpringIntegrationmessagechannelcomponents.ThisopensupalotofgreatpossibilitiestointeractwiththeSpringIntegrationtransportadaptersforFTP,TCP/IPandsoon.Inadditiontothatthemessagechannelsupportprovidesusagoodwaytoexchangemessagesinmemory.

CitrusprovidessupportforsendingandreceivingJMSmessages.Wehavetoseparatebetweensynchronousandasynchronouscommunication.SointhischapterweexplainhowtosetupJMSmessageendpointsforsynchronousandasynchronousoutboundandinboundcommunication

NoteThemessagechannelconfigurationcomponentsusethedefault"citrus"configurationnamespaceandschemadefinition.IncludethisnamespaceintoyourSpringconfigurationinordertousetheCitrusconfigurationelements.ThenamespaceURIandschemalocationareaddedtotheSpringconfigurationXMLfileasfollows.

<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:citrus-jms="http://www.citrusframework.org/schema/config"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/confighttp://www.citrusframework.org/schema/config/citrus-config.xsd">

[...]

</beans>

AfterthatyouareabletousecustomizedCitrusXMLelementsinordertodefinetheSpringbeans.

CitrusReferenceGuide

310Messagechannel

Page 311: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Channelendpoint

Citrusoffersachannelendpointcomponentthatisabletocreateproducerandconsumercomponents.Producerandconsumersendandreceivemessagesbothtoandfromachannelendpoint.BydefaulttheendpointisasynchronouswhenconfiguredintheCitrusapplicationcontext.Withthiscomponentyouareabletoaccessmessagechannelsdirectly:

<citrus:channel-endpointid="helloEndpoint"channel="helloChannel"/>

<si:channelid="helloChannel"/>

TheCitruschannelendpointreferencesaSpringIntegrationchanneldirectly.InsideyourtestcaseyoucanreferencetheCitrusendpointasusualtosendandreceivemessages.Wewillseethislaterinsomeexamplecodelistings.

NoteTheSpringIntegrationconfigurationcomponentsuseaspecificnamespacethathastobeincludedintoyourSpringapplicationcontext.Youcanusethefollowingtemplatewhichholdsallnecessarynamespacesandschemalocations:

<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:citrus="http://www.citrusframework.org/schema/config"xmlns:si="http://www.springframework.org/schema/integration"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/confighttp://www.citrusframework.org/schema/config/citrus-config.xsdhttp://www.springframework.org/schema/integrationhttp://www.springframework.org/schema/integration/spring-integration.xsd"></beans>

TheCitruschannelendpointalsosupportsacustomizedmessagechanneltemplatethatwillactuallysendthemessages.Thecustomizedtemplatemightgiveyouaccesstospecialconfigurationpossibilities.Howeveritisoptional,soifnomessagechanneltemplateisdefinedintheconfigurationCitruswillcreateadefaulttemplate.

<citrus:channel-endpointid="helloEndpoint"channel="helloChannel"message-channel-template="myMessageChannelTemplate"/>

CitrusReferenceGuide

311Messagechannel

Page 312: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Themessagesenderisnowreadytopublishmessagestothedefinedchannel.Thecommunicationissupposedtobeasynchronous,sotheproducerisnotabletoprocessareplymessage.Wewilldealwithsynchronouscommunicationandreplymessageslaterinthischapter.Themessageproducerjustpublishesmessagestothechannelandisdone.Interactingwiththeendpointsinatestcaseisquiteeasy.Justreferencetheidoftheendpointinyoursendandreceivetestactions

<sendendpoint="helloEndpoint"><message><payload><v1:HelloRequestxmlns:v1="http://citrusframework.org/schemas/HelloService.xsd"><v1:Text>HelloWorld!</v1:Text></v1:HelloRequest></payload></message></send>

<receiveendpoint="helloEndpoint"><message><payload><v1:HelloResponsexmlns:v1="http://citrusframework.org/schemas/HelloService.xsd"><v1:Text>HelloCitrus!</v1:Text></v1:HelloResponse></payload></message></receive>

AsyoucanseeCitrusisalsoabletoreceivemessagesfromthesameSpringIntegrationmessagechanneldestination.Wejustreferencesthesamechannel-endpointinthereceiveaction.

Asusualthereceiverconnectstothemessagedestinationandwaitsformessagestoarrive.Theusercansetareceivetimeoutwhichissetto5000millisecondsbydefault.Incasenomessagewasreceivedinthistimeframethereceiverraisestimeouterrorsandthetestfails.

Synchronouschannelendpoints

Thesynchronouschannelproducerpublishesmessagesandwaitssynchronouslyfortheresponsetoarriveonsomereplychanneldestination.Thereplychannelnameissetinthemessage'sheaderattributessothecounterpartinthiscommunicationcansendits

CitrusReferenceGuide

312Messagechannel

Page 313: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

replytothatchannel.Thebasicconfigurationforasynchronouschannelendpointcomponentlookslikefollows:

<citrus:channel-sync-endpointid="helloSyncEndpoint"channel="helloChannel"reply-timeout="1000"polling-interval="1000"/>

Synchronousmessagechannelendpointsusuallydopollforsynchronousreplymessagesforprocessingthereplymessages.Thepollintervalisanoptionalsettinginordertomanagetheamountofreplymessagehandshakeattempts.Oncetheendpointwasabletoreceivethereplymessagesynchronouslythetestcasecanreceivethereply.Incaseallmessagehandshakeattemptsdofailbecausethereplymessageisnotavailableintimeweraisesometimeouterrorandthetestwillfail.

NoteBydefaultthechannelendpointusestemporaryreplychanneldestinations.Thetemporaryreplychannelsareonlyusedonceforasinglecommunicationhandshake.Afterthatthereplychannelisdeletedagain.Staticreplychannelsarenotsupportedasithasnotbeeninscopeyet.

Whensendingamessagetothisendpointinthefirstplacetheproducerwillwaitsynchronouslyfortheresponsemessagetoarriveonthereplydestination.Youcanreceivethereplymessageinyourtestcaseusingthesameendpointcomponent.Sowehavetwoactionsonthesameendpoint,firstsendthenreceive.

<sendendpoint="helloSyncEndpoint"><message><payload><v1:HelloRequestxmlns:v1="http://citrusframework.org/schemas/HelloService.xsd"><v1:Text>HelloWorld!</v1:Text></v1:HelloRequest></payload></message></send>

<receiveendpoint="helloSyncEndpoint"><message><payload><v1:HelloResponsexmlns:v1="http://citrusframework.org/schemas/HelloService.xsd"><v1:Text>HelloCitrus!</v1:Text></v1:HelloResponse></payload></message></receive>

CitrusReferenceGuide

313Messagechannel

Page 314: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Inthelastsectionwesawthatsynchronouscommunicationisbasedonreplymessagesontemporaryreplychannels.WesawthatCitrusisabletopublishmessagestochannelsandwaitforreplymessagestoarriveontemporaryreplychannels.Thissectiondealswiththesamesynchronouscommunicationoverreplymessages,butnowCitrushastosenddynamicreplymessagestotemporarychannels.

ThescenariowearetalkingaboutisthatCitrusreceivesamessageandweneedtoreplytoatemporaryreplychannelthatisstoredinthemessageheaderattributes.Wehandlethissynchronouscommunicationwiththesamesynchronouschannelendpointcomponent.Wheninitiatingthecommunicationbyreceivingamessagefromasynchronouschannelendpointyouareabletosendasynchronousresponseback.Againjustusethesameendpointreferenceinyourtestcase.Thehandlingoftemporaryreplydestinationsisdoneautomaticallybehindthescenes.Sowehaveagaintwoactionsinourtestcase,butthistimefirstreceivethensend.

<receiveendpoint="helloSyncEndpoint"><message><payload><v1:HelloRequestxmlns:v1="http://citrusframework.org/schemas/HelloService.xsd"><v1:Text>HelloWorld!</v1:Text></v1:HelloRequest></payload></message></receive>

<sendendpoint="helloSyncEndpoint"><message><payload><v1:HelloResponsexmlns:v1="http://citrusframework.org/schemas/HelloService.xsd"><v1:Text>HelloCitrus!</v1:Text></v1:HelloResponse></payload></message></send>

Thesynchronousmessagechannelendpointwillhandleallreplychanneldestinationsandprovidethosebehindthescenes.

Messageselectorsonchannels

CitrusReferenceGuide

314Messagechannel

Page 315: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

UnfortunatelySpringIntegrationmessagechannelsdonotsupportmessageselectorsonheadervaluesasdescribedinmessage-selector.WithCitrusversion1.2wefoundawaytoalsoaddmessageselectorsupportonmessagechannels.Wehadtointroduceaspecialqueuemessagechannelimplementation.Sofirstofallweusethisnewmessagechannelimplementationinourconfiguration.

<citrus:channelid="orderChannel"capacity="5"/>

TheCitrusmessagechannelimplementationextendsthequeuechannelimplementationfromSpringIntegration.Sowecanaddacapacityattributeforthischannel.That'sit!Nowweusethemessagechannelthatsupportsmessageselection.Inourtestwedefinemessageselectorsonheadervaluesasdescribedinmessage-selectorandyouwillseethatitworks.

Inadditiontothatwehaveimplementedothermessagefilterpossibilitiesonmessagechannelsthatwediscussinthenextsections.

RootQNameMessageSelector

YoucanusetheXMLrootQNameofyourmessageasselectioncriteria.Let'sseehowthisworksinasmallexample:

WehavetwodifferentXMLmessagesonamessagechannelwaitingtobepickedupbyaconsumer.

<HelloMessagexmlns="http://citrusframework.org/schema">HelloCitrus</HelloMessage><GoodbyeMessagexmlns="http://citrusframework.org/schema">GoodbyeCitrus</GoodbyeMessage>

WewouldliketopickuptheGoodbyeMessageinourtestcase.TheHelloMessageshouldbeleftonthemessagechannelaswearenotinterestedinitrightnow.Wecandefinearootqnamemessageselectorinthereceiveactionlikethis:

<receiveendpoint="orderChannelEndpoint"><selector><elementname="root-qname"value="GoodbyeMessage"/></selector><message><payload><GoodbyeMessagexmlns="http://citrusframework.org/schema">GoodbyeCitrus</GoodbyeMessage</payload></message></receive>

CitrusReferenceGuide

315Messagechannel

Page 316: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TheCitrusreceiverpicksuptheGoodbyeMessagefromthechannelselectedviatherootqnameoftheXMLmessagepayload.OfcourseyoucanalsocombinemessageheaderselectorsandrootqnameselectorsasshowninthisexamplebelowwhereamessageheadersequenceIdisaddedtotheselectionlogic.

<selector><elementname="root-qname"value="GoodbyeMessage"/><elementname="sequenceId"value="1234"/></selector>

AswedealwithXMLqnamevalues,wecanalsousenamespacesinourselectorrootqnameselection.

<selector><elementname="root-qname"value="http://citrusframework.org/schemaGoodbyeMessage"/></selector>

XPathEvaluatingMessageSelector

ItisalsopossibletoevaluatesomeXPathexpressiononthemessagepayloadinordertoselectamessagefromamessagechannel.TheXPathexpressionoutcomemustmatchanexpectedvalueandonlythenthemessageisconsumedformthechannel.

ThesyntaxfortheXPathexpressionistobedefinedastheelementnamelikethis:

<selector><elementname="xpath://Order/status"value="pending"/></selector>

Themessageselectorlooksforordermessageswithstatus="pending"inthemessagepayload.Thismeansthatfollowingmessageswouldgetaccepted/declinedbythemessageselector.

<Order><status>pending</status></Order>=ACCEPTED<Order><status>finished</status></Order>=NOTACCEPTED

OfcourseyoucanalsouseXMLnamespacesinyourXPathexpressionswhenselectingmessagesfromchannels.

CitrusReferenceGuide

316Messagechannel

Page 317: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<selector><elementname="xpath://ns1:Order/ns1:status"value="pending"/></selector>

Namespaceprefixesmustmatchtheincomingmessage-otherwisetheXPathexpressionwillnotworkasexpected.Inourexamplethemessageshouldlooklikethis:

<ns1:Orderxmlns:ns1="http://citrus.org/schema"><ns1:status>pending</ns1:status></ns1:Order>

KnowingthecorrectXMLnamespaceprefixisnotalwayseasy.IfyouarenotsurewhichnamespaceprefixtochooseCitrusshipswithadynamicnamespacereplacementforXPathexpressions.TheXPathexpressionlookslikethisandismostflexible:

<selector><elementname="xpath://http://citrus.org/schema:Order/http://citrus.org/schema:status"value="pending"/></selector>

ThiswillmatchallincomingmessagesregardlesstheXMLnamespaceprefixthatisused.

CitrusReferenceGuide

317Messagechannel

Page 318: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

FilesupportInchaptermessage-channelwediscussedthenativeSpringIntegrationchannelsupportwhichenablesCitrustointeractwithallSpringIntegrationmessagingadapterimplementations.ThisisafantasticwaytoextendCitrusforadditionaltransports.ThisinteractionnowcomeshandywhenwritingandreadingfilesfromthefilesysteminCitrus.

Writefiles

WewanttousetheSpringIntegrationfileadapterforbothreadingandwritingfileswithalocaldirectory.Citruscaneasilyconnecttothisfileadapterimplementationwithitsmessagechannelsupport.CitrusmessagesenderandreceiverspeaktomessagechannelsthatareconnectedtotheSpringIntegrationfileadapters.

<citrus:channel-endpointid="fileEndpoint"channel="fileChannel"/>

<file:outbound-channel-adapterid="fileOutboundAdapter"channel="fileChannel"directory="file:$some.directory.property"/>

<si:channelid="fileChannel"/>

TheconfigurationabovedescribesaCitrusmessagechannelendpointconnectedtoaSpringIntegrationoutboundfileadapterthatwritesmessagestoastoragedirectory.WiththiscombinationyouareabletowritefilestoadirectoryinyourCitrustestcase.ThetestcaseusesthechannelendpointinitssendactionandtheendpointinteractswiththeSpringIntegrationfileadaptersosendingoutthefile.

NoteTheSpringIntegrationfileadapterconfigurationcomponentsaddanewnamespacetoourSpringapplicationcontext.Seethistemplatewhichholdsallnecessarynamespacesandschemalocations:

<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:citrus="http://www.citrusframework.org/schema/config"xmlns:si="http://www.springframework.org/schema/integration"xmlns:file="http://www.springframework.org/schema/integration/file"xsi:schemaLocation="http://www.springframework.org/schema/beans

CitrusReferenceGuide

318File

Page 319: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/confighttp://www.citrusframework.org/schema/config/citrus-config.xsdhttp://www.springframework.org/schema/integrationhttp://www.springframework.org/schema/integration/spring-integration.xsdhttp://www.springframework.org/schema/integration/filehttp://www.springframework.org/schema/integration/file/spring-integration-file.xsd"></beans>

Readfiles

Thenextprogramlistingshowsapossibleinboundfilecommunication.SotheSpringIntegrationfileinboundadapterwillreadfilesfromastoragedirectoryandpublishthefilecontentstoamessagechannel.Citruscanthenreceivethosefilesasmessagesinatestcaseviathechannelendpointandvalidatethefilecontentsforinstance.

<file:inbound-channel-adapterid="fileInboundAdapter"channel="fileChannel"directory="file:$some.directory.property"><si:pollerfixed-rate="100"/></file:inbound-channel-adapter>

<si:channelid="fileChannel"><si:queuecapacity="25"/><si:interceptors><beanclass="org.springframework.integration.transformer.MessageTransformingChannelInterceptor"<constructor-arg><beanclass="org.springframework.integration.file.transformer.FileToStringTransformer"</constructor-arg></bean></si:interceptors></si:channel>

<citrus:channel-endpointid="fileEndpoint"channel="fileChannel"/>

ImportantThefileinboundadapterconstructsJavafileobjectsasthemessagepayloadbydefault.CitruscanonlyworkonStringmessagepayloads.SoweneedafiletransformerthatconvertsthefileobjectstoStringpayloadsrepresentingthefile'scontent.

ThisfileadapterexampleshowshoweasyCitruscanworkhandinhandwithSpringIntegrationadapterimplementations.ThemessagechannelsupportisafantasticwaytoextendthetransportandprotocolsupportinCitrusbyconnectingwiththeverygood

CitrusReferenceGuide

319File

Page 320: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

SpringIntegrationadapterimplementations.HaveacloserlookattheSpringIntegrationprojectformoredetailsandotheradapterimplementationsthatyoucanusewithCitrusintegrationtesting.

CitrusReferenceGuide

320File

Page 321: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ApacheCamelsupportApacheCamelprojectimplementstheenterpriseintegrationpatternsforbuildingmediationandroutingrulesinyourenterpriseapplication.WiththeCitrusCamelsupportyouareabletodirectlyinteractwiththeApacheCamelcomponentsandroutedefinitions.YoucancallCamelroutesandreceivesynchronousresponsemessages.YoucanalsosimulatetheCamelrouteendpointwithreceivingmessagesandprovidingsimulatedresponsemessages.

NoteThecamelcomponentsinCitrusarekeptinaseparateMavenmodule.SoyoushouldaddthemoduleasMavendependencytoyourprojectaccordingly.

<dependency><groupId>com.consol.citrus</groupId><artifactId>citrus-camel</artifactId><version>2.7.1</version></dependency>

CitrusprovidesaspecialApacheCamelconfigurationschemathatisusedinourSpringconfigurationfiles.Youhavetoincludethecitrus-camelnamespaceinyourSpringconfigurationXMLfilesasfollows.

<beansxmlns="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-camel="http://www.citrusframework.org/schema/camel/config"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/confighttp://www.citrusframework.org/schema/config/citrus-config.xsdhttp://www.citrusframework.org/schema/camel/confighttp://www.citrusframework.org/schema/camel/config/citrus-camel-config.xsd">

[...]

</beans>

NowyouarereadytousetheCitrusApacheCamelconfigurationelementsusingthecitrus-camelnamespaceprefix.

ThenextsectionsexplaintheCitruscapabilitieswhileworkingwithApacheCamel.

CitrusReferenceGuide

321Camel

Page 322: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Camelendpoint

CamelandCitrusbothusetheendpointpatterninordertodefinemessagedestinations.Userscaninteractwiththeseendpointswhencreatingthemediationandroutinglogic.TheCitrusendpointcomponentforCamelinteractionisdefinedasfollowsinyourCitrusSpringconfiguration.

<citrus-camel:endpointid="directCamelEndpoint"endpoint-uri="direct:news"/>

RightnexttothatCitrusendpointweneedtheApacheCamelroutethatislocatedinsideacamelcontextcomponent.

<camelContextid="camelContext"xmlns="http://camel.apache.org/schema/spring"><routeid="newsRoute"><fromuri="direct:news"/><touri="log:com.consol.citrus.camel?level=INFO"/><touri="seda:news-feed"/></route></camelContext>

AsyoucanseetheCitruscamelendpointisabletointeractwiththeCamelroute.IntheexampleabovetheCamelcontextisplacedasSpringbeanCamelcontext.ThiswouldbetheeasiestsetuptouseCamelwithCitrusasyoucanaddtheCamelcontextstraighttotheSpringbeanapplicationcontext.OfcourseyoucanalsoimportyourCamelcontextandroutesfromotherSpringbeancontextfilesoryoucanstarttheCamelcontextrouteswithJavacode.

IntheexampletheApacheCamelrouteislisteningontherouteendpointuridirect:news.IncomingmessageswillbeloggedtotheconsoleusingalogCamelcomponent.AfterthatthemessageisforwardedtoasedaCamelcomponentwhichisasimplequeueinmemory.SowehaveasmallCamelroutinglogicwithtwodifferentmessagetransports.

TheCitrusendpointcaninteractwiththissampleroutedefinition.TheendpointconfigurationholdstheendpointuriinformationthattellsCitrushowtoaccesstheApacheCamelroutedestination.ThisendpointuricanbeanyCamelendpointurithatisusedinaCamelroute.Herewejustusethedirectendpointuridirect:newssothesampleCamelroutegetscalleddirectly.Inyourtestcaseyoucanusethisendpoint

CitrusReferenceGuide

322Camel

Page 323: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

componentreferencedbyitsidornameinordertosendandreceivemessagesontherouteaddressdirect:news.TheCamelroutelisteningonthisdirectaddresswillbeinvokedaccordingly.

TheApacheCamelroutessupportasynchronousandsynchronousmessagecommunicationpatterns.BydefaultCitrususesasynchronouscommunicationwithCamelroutes.ThismeansthattheCitrusproducersendstheexchangemessagetotherouteendpointuriandisfinishedimmediately.Thereisnosynchronousresponsetoawait.IncontrarytothatthesynchronousendpointwillsendandreceiveasynchronousmessageontheCameldestinationroute.Wewilldiscussthislateroninthischapter.FornowwehavealookonhowtousetheCitruscamelendpointinatestcaseinordertosendamessagetotheCamelroute:

<sendendpoint="directCamelEndpoint"><messagetype="plaintext"><payload>HellofromCitrus!</payload></message></send>

TheCitruscamelendpointcomponentcanalsobeusedinareceivemessageactioninyourtestcase.Inthissituationyouwouldreceiveamessagefromtherouteendpoint.ThisisespeciallydesignedforqueueingendpointroutessuchastheCamelsedacomponent.InourexampleCamelrouteabovethesedaCamelcomponentiscalledwiththeendpointuriseda:news-feed.ThismeansthattheCamelrouteissendingamessagetothesedacomponent.Citrusisabletoreceivethisroutemessagewithaendpointcomponentlikethis:

<citrus-camel:endpointid="sedaCamelEndpoint"endpoint-uri="seda:news-feed"/>

YoucanusetheCitruscamelendpointinyourtestcasereceiveactioninordertoconsumethemessageonthesedacomponent.

<receiveendpoint="sedaCamelEndpoint"><messagetype="plaintext"><payload>HellofromCitrus!</payload></message></receive>

CitrusReferenceGuide

323Camel

Page 324: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TipInsteadofdefiningastaticCitruscamelcomponentyoucouldalsousethedynamicendpointcomponentsinCitrus.Thiswouldenableyoutosendyourmessagedirectlyusingtheendpointuridirect:newsinyourtestcase.Readmoreaboutthisinendpoint-components.

CitrusisabletosendandreceivemessageswithCamelrouteendpointuri.ThisenablesyoutoinvokeaCamelroute.TheCamelcomponentsusedisdefinedbytheendpointuriasusual.WheninteractingwithCamelroutesyoumightneedtosendbacksomeresponsemessagesinordertosimulateboundaryapplications.Wewilldiscussthesynchronouscommunicationinthenextsection.

SynchronousCamelendpoint

ThesynchronousApacheCamelproducersendsamessagetosomerouteandwaitssynchronouslyfortheresponsetoarrive.InCamelthiscommunicationisrepresentedwiththeexchangepatternInOut.ThebasicconfigurationforasynchronousApacheCamelendpointcomponentlookslikefollows:

<citrus-camel:sync-endpointid="camelSyncEndpoint"endpoint-uri="direct:hello"timeout="1000"polling-interval="300"/>

Synchronousendpointspollforsynchronousreplymessagestoarrive.Thepollintervalisanoptionalsettinginordertomanagetheamountofreplymessagehandshakeattempts.Oncetheendpointwasabletoreceivethereplymessagesynchronouslythetestcasecanreceivethereply.Incasethereplymessageisnotavailableintimeweraisesometimeouterrorandthetestwillfail.

Inafirsttestscenariowewriteatestcasethesendsamessagetothesynchronousendpointandwaitsforthesynchronousreplymessagetoarrive.SowehavetwoactionsonthesameCitrusendpoint,firstsendthenreceive.

<sendendpoint="camelSyncEndpoint"><messagetype="plaintext"><payload>HellofromCitrus!</payload></message></send>

<receiveendpoint="camelSyncEndpoint"><messagetype="plaintext"><payload>ThisisthereplyfromApacheCamel!</payload>

CitrusReferenceGuide

324Camel

Page 325: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</message></receive>

Thenextvariationdealswiththesamesynchronouscommunication,butsendandreceiverolesareswitched.NowCitrusreceivesamessagefromaCamelrouteandhastoprovideareplymessage.WehandlethissynchronouscommunicationwiththesamesynchronousApacheCamelendpointcomponent.Onlydifferenceisthatweinitiallystartthecommunicationbyreceivingamessagefromtheendpoint.KnowingthisCitrusisabletosendasynchronousresponseback.Againjustusethesameendpointreferenceinyourtestcase.Sowehaveagaintwoactionsinourtestcase,butthistimefirstreceivethensend.

<receiveendpoint="camelSyncEndpoint"><messagetype="plaintext"><payload>HellofromApacheCamel!</payload></message></receive>

<sendendpoint="camelSyncEndpoint"><messagetype="plaintext"><payload>ThisisthereplyfromCitrus!</payload></message></send>

Thisisprettysimple.CitrustakescareonsettingtheApacheCamelexchangepatternInOutwhileusingsynchronouscommunications.TheCamelroutesdorespondandCitrusisabletoreceivethesynchronousmessagesaccordingly.WiththispatternyoucaninteractwithApacheCamelrouteswhereCitrussimulatessynchronousclientsandconsumers.

Camelexchangeheaders

ApacheCamelusesexchangeswhensendingandreceivingmessagestoandfromroutes.Theseexchangesholdspecificinformationonthecommunicationoutcome.Citrusautomaticallyconvertstheseexchangeinformationtospecialmessageheaderentries.Youcanvalidatethoseexchangeheaderstheneasilyinyourtestcase:

<receiveendpoint="sedaCamelEndpoint"><messagetype="plaintext"><payload>HellofromCamel!</payload></message><header>

CitrusReferenceGuide

325Camel

Page 326: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<elementname="citrus_camel_route_id"value="newsRoute"/><elementname="citrus_camel_exchange_id"value="ID-local-50532-1402653725341-0-3"/><elementname="citrus_camel_exchange_failed"value="false"/><elementname="citrus_camel_exchange_pattern"value="InOnly"/><elementname="CamelCorrelationId"value="ID-local-50532-1402653725341-0-1"/><elementname="CamelToEndpoint"value="seda://news-feed"/></header></receive>

BesidestheCamelspecificexchangeinformationtheCamelexchangedoesalsoholdsomecustomproperties.ThesepropertiessuchasCamelToEndpointorCamelCorrelationIdarealsoaddedautomaticallytotheCitrusmessageheadersocanexpecttheminareceivemessageaction.

Camelexceptionhandling

Letussupposefollowingroutedefinition:

<camelContextid="camelContext"xmlns="http://camel.apache.org/schema/spring"><routeid="newsRoute"><fromuri="direct:news"/><touri="log:com.consol.citrus.camel?level=INFO"/><touri="seda:news-feed"/><onException><exception>com.consol.citrus.exceptions.CitrusRuntimeException</exception><touri="seda:exceptions"/></onException></route></camelContext>

Theroutehasanexceptionhandlingblockdefinedthatiscalledassoonastheexchangeprocessingendsupinsomeerrororexception.WithCitrusyoucanalsosimulateaexchangeexceptionwhensendingbackasynchronousresponsetoacallingroute.

<sendendpoint="sedaCamelEndpoint"><messagetype="plaintext"><payload>Somethingwentwrong!</payload></message><header><elementname="citrus_camel_exchange_exception"value="com.consol.citrus.exceptions.CitrusRuntimeException"/><elementname="citrus_camel_exchange_exception_message"value="Somethingwentwrong!"/><elementname="citrus_camel_exchange_failed"value="true"/></header>

CitrusReferenceGuide

326Camel

Page 327: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</send>

Thismessageasresponsetotheseda:news-feedroutewouldcauseCameltoentertheexceptionhandlingintheroutedefinition.Theexceptionhandlingisactivatedandcallstheerrorhandlingrouteendpointseda:exceptions.OfcourseCitruswouldbeabletoreceivesuchanexceptionexchangevalidatingtheexceptionhandlingoutcome.

InsuchfailurescenariostheApacheCamelexchangeholdstheexceptioninformation(CamelExceptionCaught)suchascausingexceptionclassanderrormessage.TheseheadersarepresentinanerrorscenarioandcanbevalidatedinCitruswhenreceivingerrormessagesasfollows:

<receiveendpoint="errorCamelEndpoint"><messagetype="plaintext"><payload>Somethingwentwrong!</payload></message><header><elementname="citrus_camel_route_id"value="newsRoute"/><elementname="citrus_camel_exchange_failed"value="true"/><elementname="CamelExceptionCaught"value="com.consol.citrus.exceptions.CitrusRuntimeException:Somethingwentwrong!"/></header></receive>

ThiscompletesthebasicexceptionhandlinginCitruswhenusingtheApacheCamelendpoints.

Camelcontexthandling

IntheprevioussampleswehaveusedtheApacheCamelcontextasSpringbeancontextthatisautomaticallyloadedwhenCitrusstartsup.NowwhenusingasingleCamelcontextinstanceCitrusisabletoautomaticallypickthisCamelcontextforrouteinteraction.IfyouusemorethatoneCamelcontextyouhavetotelltheCitrusendpointcomponentwhichcontexttouse.Theendpointoffersanoptionalattributecalledcamel-context.

<citrus-camel:endpointid="directCamelEndpoint"camel-context="newsContext"endpoint-uri="direct:news"/>

<camelContextid="newsContext"xmlns="http://camel.apache.org/schema/spring">

CitrusReferenceGuide

327Camel

Page 328: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<routeid="newsRoute"><fromuri="direct:news"/><touri="log:com.consol.citrus.camel?level=INFO"/><touri="seda:news-feed"/></route></camelContext>

<camelContextid="helloContext"xmlns="http://camel.apache.org/schema/spring"><routeid="helloRoute"><fromuri="direct:hello"/><touri="log:com.consol.citrus.camel?level=INFO"/><touri="seda:hello"/></route></camelContext>

IntheexampleabpovewehavetwoCamelcontextinstancesloaded.Theendpointhastopickthecontexttousewiththeattributecamel-contextwhichresidestotheSpringbeanidoftheCamelcontext.

Camelrouteactions

SinceCitrus2.4weintroducedsomeCamelspecifictestactionsthatenableeasyinteractionwithCamelroutesandtheCamelcontext.ThetestactionsdofollowaspecificXMLnamespacesowehavetoaddthisnamespacetothetestcasewhenusingtheactions.

<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:camel="http://www.citrusframework.org/schema/camel/testcase"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/camel/testcasehttp://www.citrusframework.org/schema/camel/testcase/citrus-camel-testcase.xsd">

[...]

</beans>

Weaddedaspecialcamelnamespacewithprefixcamel:sonowwecanstarttoaddCameltestactionstothetestcase:

XMLDSL

<testcasename="CamelRouteIT">

CitrusReferenceGuide

328Camel

Page 329: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<actions><camel:create-routes><routeContextxmlns="http://camel.apache.org/schema/spring"><routeid="route_1"><fromuri="direct:test1"/><touri="mock:test1"/></route>

<routeid="route_2"><fromuri="direct:test2"/><touri="mock:test2"/></route></routeContext></camel:create-routes>

<camel:create-routescamel-context="camelContext"><routeContextxmlns="http://camel.apache.org/schema/spring"><route><fromuri="direct:test3"/><touri="mock:test3"/></route></routeContext></camel:create-routes></actions></testcase>

Intheexampleabovewehaveusedthecamel:create-routetestactionthatwillcreatenewCamelroutesatruntimeintheCamelcontext.ThetargetCamelcontextisspecifiedwiththeoptionalcamel-contextattribute.BydefaultCitruswillsearchforaCamelcontextavailableintheSpringbeanapplicationcontext.Removingroutesatruntimeisalsosupported.

XMLDSL

<testcasename="CamelRouteIT"><actions><camel:remove-routescamel-context="camelContext"><routeid="route_1"/><routeid="route_2"/><routeid="route_3"/></camel:remove-routes></actions></testcase>

NextoperationwewilldiscussisthestartandstopofexistingCamelroutes:

XMLDSL

CitrusReferenceGuide

329Camel

Page 330: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<testcasename="CamelRouteIT"><actions><camel:start-routescamel-context="camelContext"><routeid="route_1"/></camel:start-routes>

<camel:stop-routescamel-context="camelContext"><routeid="route_2"/><routeid="route_3"/></camel:stop-routes></actions></testcase>

StartingandstoppingCamelroutesatruntimeisimportantwhentemporarilyCitrusneedtoreceiveamessageonaCamelendpointURI.Wecanstoparoute,useaCitruscamelendpointinsteadforvalidationandstarttherouteafterthetestisdone.ThiswaywencanalsosimulateerrorsandfailurescenariosinaCamelrouteinteraction.

OfcourseallCamelrouteactionsarealsoavailableinJavaDSL.

JavaDSL

@AutowiredprivateCamelContextcamelContext;

@CitrusTestpublicvoidcamelRouteTest()camel().context(camelContext).create(newRouteBuilder(camelContext)@Overridepublicvoidconfigure()throwsExceptionfrom("direct:news").routeId("route_1").autoStartup(false).setHeader("headline",simple("ThisisBIGnews!")).to("mock:news");

from("direct:rumors").routeId("route_2").autoStartup(false).setHeader("headline",simple("Thisisjustarumor!")).to("mock:rumors"););

camel().context(camelContext).start("route_1","route_2");

camel().context(camelContext).stop("route_2");

camel().context(camelContext).remove("route_2");

CitrusReferenceGuide

330Camel

Page 331: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

AsyoucanseewehaveaccesstotheCamelroutebuilderthatadds1-nnewCamelroutestothecontext.Afterthatwecanstart,stopandremovetherouteswithinthetestcase.

Camelcontrolbusactions

TheCamelcontrolbuscomponentisagoodwaytoaccessroutestatisticsandroutestatusinformationwithinaCamelcontext.Citrusprovidescontrolbustestactionstoeasilyaccessthecontrolbusoperationsatruntime.

XMLDSL

<testcasename="CamelControlBusIT"><actions><camel:control-bus><camel:routeid="route_1"action="start"/></camel:control-bus>

<camel:control-buscamel-context="camelContext"><camel:routeid="route_2"action="status"/><camel:result>Stopped</camel:result></camel:control-bus>

<camel:control-bus><camel:languagetype="simple">$camelContext.stop()</camel:language></camel:control-bus>

<camel:control-buscamel-context="camelContext"><camel:languagetype="simple">$camelContext.getRouteStatus('route_3')</camel:language<camel:result>Started</camel:result></camel:control-bus></actions></testcase>

Theexampletestcaseshowsthecontrolbusaccess.Camelprovidestwodifferentwaystospecifyoperationsandparameters.Thefirstoptionistheuseofanactionattribute.TheCamelrouteidhastobespecifiedasmandatoryattribute.Asaresultthecontrolbusactionwillbeexecutedonthetargetrouteduringtestruntime.ThiswaywecanalsostartandstopCamelroutesinaCamelcontext.

CitrusReferenceGuide

331Camel

Page 332: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Incaseancontrolbusoperationhasaresultsuchasthestatusactionwecanspecifyacontrolresultthatiscompared.Citruswillraisevalidationexceptionswhentheresultsdiffer.Thesecondoptionforexecutingacontrolbusactionisthelanguageexpression.WecanuseCamellanguageexpressionsontheCamelcontextforaccessingacontrolbusoperation.Alsoherewecandefineanoptionaloutcomeasexpectedresult.

TheJavaDSLalsosupportsthesecontrolbusoperationsasthenextexampleshows:

JavaDSL

@AutowiredprivateCamelContextcamelContext;

@CitrusTestpublicvoidcamelRouteTest()camel().controlBus().route("my_route","start");

camel().controlBus().language(SimpleBuilder.simple("$camelContext.getRouteStatus('my_route')")).result(ServiceStatus.Started);

TheJavaDSLworkswithCamellanguageexpressionbuildersaswellasServiceStatusenumvaluesasexpectedresult.

CitrusReferenceGuide

332Camel

Page 333: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Vert.xeventbussupportVert.xisanapplicationplatformfortheJVMthatprovidesanetworkeventbusforlightweightscalablemessagingsolutions.TheCitrusVert.xcomponentsdoparticipateonthateventbusmessagingasproducerorconsumer.WiththesecomponentsyoucanaccessVert.xinstancesavailableinyournetworkinordertotestthoseVert.xapplicationsinsomeintegrationtestscenario.

NoteTheVert.xcomponentsinCitrusarekeptinaseparateMavenmodule.SoyoushouldaddthemoduleasMavendependencytoyourprojectaccordingly.

<dependency><groupId>com.consol.citrus</groupId><artifactId>citrus-vertx</artifactId><version>2.7.1</version></dependency>

CitrusprovidesaspecialVert.xconfigurationschemathatisusedinourSpringconfigurationfiles.Youhavetoincludethecitrus-vertxnamespaceinyourSpringconfigurationXMLfilesasfollows.

<beansxmlns="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-vertx="http://www.citrusframework.org/schema/vertx/config"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/confighttp://www.citrusframework.org/schema/config/citrus-config.xsdhttp://www.citrusframework.org/schema/vertx/confighttp://www.citrusframework.org/schema/vertx/config/citrus-vertx-config.xsd">

[...]

</beans>

NowyouarereadytousetheCitrusVert.xconfigurationelementsusingthecitrus-vertxnamespaceprefix.

ThenextsectionsdiscusssendingandreceivingoperationsontheVert.xeventbuswithCitrus.

CitrusReferenceGuide

333Vertx

Page 334: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Vert.xendpoint

AsusualCitrususesanendpointcomponentinordertospecifysomemessagedestinationtosendandreceivemessagestoandfrom.TheVert.xendpointcomponentisdefinedasfollowsinyourCitrusSpringconfiguration.

<citrus-vertx:endpointid="simpleVertxEndpoint"host="localhost"port="5001"pubSubDomain="false"address="news-feed"/>

<beanid="vertxInstanceFactory"class="com.consol.citrus.vertx.factory.CachingVertxInstanceFactory"

TheendpointholdssomegeneralinformationhowtoaccesstheVert.xeventbus.HostandportvaluesdefinetheVert.xHazelcastclusterhostnameandport.CitrusstartsanewVert.xinstanceusingthiscluster.SoallotherVert.xinstancesconnectedtothisclusterhostwillreceivetheeventbusmessagesfromCitrusduringthetest.Inyourtestcaseyoucanusethisendpointcomponentreferencedbyitsidornameinordertosendandreceivemessagesontheeventbusaddressnews-feed.InVert.xtheeventbusaddressdefinesthedestinationforeventconsumerstolistenon.Asalreadymentionedclusterhostnameandportareoptional,soCitruswilluselocalhostandanewrandomportontheclusterhostifnothingisspecified.

TheVert.xeventbussupportspublish-subscribeandpoint-to-pointmessagecommunicationpatterns.BydefaultthepubSubDomaininCitrusisfalsesotheeventbussenderwillinitiateapoint-to-pointcommunicationontheeventbusaddress.Thismeansthatonlyonesingleconsumerontheeventbusaddresswillreceivethemessage.Iftherearemoreconsumersontheaddressthefirsttocomewinsandreceivesthemessage.Incontrarytothatthepublish-subscribescenariowoulddeliverthemessagetoallavailableconsumersontheeventbusaddresssimultaneously.YoucanenablethepubSubDomainontheVert.xendpointcomponentforthiscommunicationpattern.

TheVert.xendpointneedsainstancefactoryimplementationinordertocreatetheembeddedVert.xinstance.BydefaultthebeannamevertxInstanceFactoryisrecognizedbyallVert.xendpointcomponents.WewilltalkaboutVert.xinstancefactoriesinmoredetaillateroninthischapter.

CitrusReferenceGuide

334Vertx

Page 335: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

AsmessagecontentyoucansendandreceiveJSONobjectsorsimplecharactersequencestotheeventbus.LetushavealookatasimplesamplesendingactionthatusesthenewVert.xendpointcomponent:

<sendendpoint="simpleVertxEndpoint"><messagetype="plaintext"><payload>HellofromCitrus!</payload></message></send>

AstheVert.xCitrusendpointisbidirectionalyoucanalsoreceivemessagesfromtheeventbus.

<receiveendpoint="simpleVertxEndpoint"><messagetype="plaintext"><payload>HellofromVert.x!</payload></message><header><elementname="citrus_vertx_address"value="news-feed"/></header></receive>

Citrusautomaticallyaddssomespecialmessageheaderstothemessage,soyoucanvalidatetheVert.xeventbusaddress.ThiscompletesthesimplesendandreceiveoperationsonaVert.xeventbus.NowletsmoveontosynchronousendpointswhereCitruswaitsforareplyontheeventbus.

SynchronousVert.xendpoint

ThesynchronousVert.xeventbusproducersendsamessageandwaitssynchronouslyfortheresponsetoarriveonsomereplyaddressdestination.Thereplyaddressnameisgeneratedautomaticallyandsetintherequestmessageheaderattributessothereceivingcounterpartinthiscommunicationcansenditsreplytothateventbusaddress.ThebasicconfigurationforasynchronousVert.xendpointcomponentlookslikefollows:

<citrus-vertx:sync-endpointid="vertxSyncEndpoint"address="hello"timeout="1000"polling-interval="300"/>

CitrusReferenceGuide

335Vertx

Page 336: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Synchronousendpointspollforsynchronousreplymessagestoarriveontheeventbusreplyaddress.Thepollintervalisanoptionalsettinginordertomanagetheamountofreplymessagehandshakeattempts.Oncetheendpointwasabletoreceivethereplymessagesynchronouslythetestcasecanreceivethereply.Incaseallmessagehandshakeattemptsdofailbecausethereplymessageisnotavailableintimeweraisesometimeouterrorandthetestwillfail.

NoteTheVert.xendpointusestemporaryreplyaddressdestinations.Thetemporaryreplyaddressingeneratedandisonlyusedonceforasinglecommunicationhandshake.Afterthatthereplyaddressisdismissedagain.

WhensendingamessagetothesynchronousVert.xendpointtheproducerwillwaitsynchronouslyfortheresponsemessagetoarriveonthereplyaddress.Youcanreceivethereplymessageinyourtestcaseusingthesameendpointcomponent.Sowehavetwoactionsonthesameendpoint,firstsendthenreceive.

<sendendpoint="vertxSyncEndpoint"><messagetype="plaintext"><payload>HellofromCitrus!</payload></message></send>

<receiveendpoint="vertxSyncEndpoint"><messagetype="plaintext"><payload>ThisisthereplyfromVert.x!</payload></message></receive>

Inthelastsectionwesawthatsynchronouscommunicationisbasedonreplymessagesontemporaryreplyeventbusaddress.WesawthatCitrusisabletosendmessagestoeventbusaddressandwaitforreplymessagestoarrive.Thisnextsectiondealswiththesamesynchronouscommunication,butsendandreceiverolesareswitched.NowCitrusreceivesamessageandhastosendareplymessagetoatemporaryreplyaddress.

WehandlethissynchronouscommunicationwiththesamesynchronousVert.xendpointcomponent.Onlydifferenceisthatweinitiallystartthecommunicationbyreceivingamessagefromtheendpoint.KnowingthisCitrusisabletosendasynchronousresponseback.Againjustusethesameendpointreferenceinyourtestcase.Thehandlingofthetemporaryreplyaddressisdoneautomaticallybehindthescenes.Sowehaveagaintwoactionsinourtestcase,butthistimefirstreceivethensend.

<receiveendpoint="vertxSyncEndpoint">

CitrusReferenceGuide

336Vertx

Page 337: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<messagetype="plaintext"><payload>HellofromVert.x!</payload></message></receive>

<sendendpoint="vertxSyncEndpoint"><messagetype="plaintext"><payload>ThisisthereplyfromCitrus!</payload></message></send>

ThesynchronousmessageendpointforVert.xeventbuscommunicationwillhandleallreplyaddressdestinationsandprovidethosebehindthescenes.

Vert.xinstancefactory

CitrusstartsanembeddedVert.xinstanceatruntimeinordertoparticipateintheVert.xcluster.WithinthisclustermultipleVert.xinstancesareconnectedviatheeventbus.ForstartingtheVert.xeventbusCitrususesaclusterhostnameandportdefinition.Youcancustomizethisclusterhostinordertoconnecttoaveryspecialclusterinyournetwork.

NowCitrusneedstomanagetheVert.xinstancescreatedduringthetestrun.BydefaultCitruswilllookforainstancefactorybeannamedvertxInstanceFactory.Youcanchoosethefactoryimplementationtouseinyourproject.BydefaultyoucanusethecachingfactoryimplementationthatcachestheVert.xinstancessowedonotconnectmorethanoneVert.xinstancetothesameclusterhost.Citrusoffersfollowinginstancefactoryimplementations:

com.consol.citrus.vertx.factory.CachingVertxInstanceFactory-defaultimplementationthatreusestheVert.xinstancebasedongivenclusterhostandport.Withthisimplementationweensureto

connectasingleCitrusVert.xinstancetoaclusterhost.

com.consol.citrus.vertx.factory.SingleVertxInstanceFactory-createsasingleVert.xinstanceandreusesthisinstanceforallendpoints.YoucanalsosetyourverycustomVert.xinstanceviaconfiguration

forcustomVert.xinstantiation.

CitrusReferenceGuide

337Vertx

Page 338: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TheinstancefactoryimplementationsdoimplementtheVertxInstanceFactoryinterface.Soyoucanalsoprovideyourveryspecialimplementation.BydefaultCitruslooksforabeannamedvertxInstanceFactorybutyoucanalsodefineyourveryspecialfactoryimplementationonmanendpointcomponent.TheVert.xinstancefactoryissetontheVert.xendpointasfollows:

<citrus-vertx:endpointid="vertxHelloEndpoint"address="hello"vertx-factory="singleVertxInstanceFactory"/>

<beanid="singleVertxInstanceFactory"class="com.consol.citrus.vertx.factory.SingleVertxInstanceFactory"/>

CitrusReferenceGuide

338Vertx

Page 339: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

MailsupportSendingandreceivingmailsisthenextinterestwearegoingtotalkabout.WhendealingwithmailcommunicationyoumostcertainlyneedtointeractwithsomesortofIMAPorPOPmailserver.ButinCitruswedonotwanttomanagemailsinapersonalinbox.Wejustneedtobeabletoexchangemailmessagesthepersistinginauserinboxisnotpartofourbusiness.

ThisiswhyCitrusprovidesjustaSMTPmailserverwhichacceptsmailmessagesfromclients.OncetheSMTPserverhasacceptedanincomingmailitforwardsthosedatatotherunningtestcase.Inthetestcaseyoucanreceivetheincomingmailmessageandperformmessagevalidationasusual.ThemailsendingpartiseasyasCitrusoffersamailclientthatconnectstosomeSMTPserverforsendingmailstotheoutsideworld.

NoteThemailcomponentsinCitrusarekeptinaseparateMavenmodule.SoyoushouldcheckthatthemoduleisavailableasMavendependencyinyourproject

<dependency><groupId>com.consol.citrus</groupId><artifactId>citrus-mail</artifactId><version>2.7.1</version></dependency>

AsusualCitrusprovidesacustomizedmailconfigurationschemathatisusedinSpringconfigurationfiles.Simplyincludethecitrus-mailnamespaceintheconfigurationXMLfilesasfollows.

<beansxmlns="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-mail="http://www.citrusframework.org/schema/mail/config"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/confighttp://www.citrusframework.org/schema/config/citrus-config.xsdhttp://www.citrusframework.org/schema/mail/confighttp://www.citrusframework.org/schema/mail/config/citrus-mail-config.xsd">

[...]

</beans>

CitrusReferenceGuide

339Mail

Page 340: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

NowyouarereadytousethecustomizedHttpconfigurationelementswiththecitrus-mailnamespaceprefix.

ReadthenextsectioninordertofindoutmoreaboutthemailmessagesupportinCitrus.

Mailclient

Themailsendingpartisquiteeasyandstraightforward.WejustneedtosendamailmessagetosomeSMTPserver.SoCitrusprovidesamailclientthatsendsoutmailmessages.

<citrus-mail:clientid="simpleMailClient"host="localhost"port="25025"/>

ThisishowaCitrusmailclientcomponentisdefinedintheSpringapplicationcontext.Youcanusethisclientreferencedbyitsidornameinyourtestcaseinamessagesendingaction.TheclientdefinesahostandportattributewhichshouldconnecttheclienttosomeSMTPserverinstance.

Weallknowmailmessagecontents.Themailmessagehassomegeneralpropertiessetbytheuser:

from:Themessagesendermailaddressto:Themessagerecipientmailaddress.Youcanaddmultiplerecipientsbyusingacommaseparatedlist.cc:Copyrecipientmailaddress.Youcanaddmultiplerecipientsbyusingacommaseparatedlist.bcc:Blindcopyrecipientmailaddress.Youcanaddmultiplerecipientsbyusingacommaseparatedlist.subject:Somesubjectusedasmailheadline.

Asatesteryouareabletosetthesepropertiesinyourtestcase.CitrusdefinesaXMLmailmessagerepresentationthatyoucanuseinsideyoursendaction.Letushavealookatthis:

<sendendpoint="simpleMailClient"><message><payload><mail-messagexmlns="http://www.citrusframework.org/schema/mail/message"><from>[email protected]</from>

CitrusReferenceGuide

340Mail

Page 341: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<to>[email protected]</to><cc></cc><bcc></bcc><subject>Thisisatestmailmessage</subject><body><contentType>text/plain;charset=utf-8</contentType><content>HelloCitrusmailserver!</content></body></mail-message></payload></message></send>

ThebasicXMLmailmessagerepresentationdefinesalistofbasicmailpropertiessuchasfrom,toorsubject.InadditiontothatwedefineatextbodywhichiseitherplaintextorHTML.Youcanspecifythecontenttypeofthemailbodyveryeasy(e.g.text/plainortext/html).BydefaultCitrususestext/plaincontenttype.

Nowwhendealingwithmailmessagesyouoftencometousemultipartstructuresforattachments.InCitrusyoucandefineattachmentcontentasbase64charactersequence.TheCitrusmailclientwillautomaticallycreateapropermultipartmailmimemessageusingthecontenttypesandbodypartsspecified.

<sendendpoint="simpleMailClient"><message><payload><mail-messagexmlns="http://www.citrusframework.org/schema/mail/message"><from>[email protected]</from><to>[email protected]</to><cc></cc><bcc></bcc><subject>Thisisatestmailmessage</subject><body><contentType>text/plain;charset=utf-8</contentType><content>HelloCitrusmailserver!</content><attachments><attachment><contentType>text/plain;charset=utf-8</contentType><content>Thisisattachmentdata</content><fileName>attachment.txt</fileName></attachment></attachments></body></mail-message></payload></message></send>

CitrusReferenceGuide

341Mail

Page 342: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Thatcompletesthebasicmailclientcapabilities.Butwaitwehavenottalkedabouterrorscenarioswheremailcommunicationresultsinerror.Whenrunningintomailerrorscenarioswehavetohandletheerrorrespectivelywithexceptionhandling.WhenthemailserverrespondedwitherrorsCitruswillraisemailexceptionsautomaticallyandyourtestcasefailsaccordingly.

Asatesteryoucancatchandassertthesemailexceptionsverifyingyourerrorscenario.

<assertexception="org.springframework.mail.MailSendException"><when><sendendpoint="simpleMailClient"><message><payload><mail-messagexmlns="http://www.citrusframework.org/schema/mail/message">[...]</mail-message></payload></message></send></when><assert/>

WeasserttheMailSendExceptionfromSpringtobethrownwhilesendingthemailmessagetotheSMTPserver.Withexceptionmessagevalidationyouareabletoexpectveryspecificmailsenderrorsontheclientside.Thisishowyoucanhandlesomesortoferrorsituationreturnedbythemailserver.SpeakingofmailserversweneedtoalsotalkaboutprovidingamailserverendpointinCitrusforclients.Thisispartofournextsection.

Mailserver

Consumingmailmessagesisamorecomplicatedtaskasweneedtohavesomesortofserverthatclientscanconnectto.InyourmailclientsoftwareyoutypicallypointtosomeIMAPorPOPinboxandreceivemailsfromthatendpoint.InCitruswedonotwanttomanageawholepersonalmailinboxsuchasIMAPorPOPwouldprovide.WejustneedaSMTPserverendpointforclientstosendmailsto.TheSMTPserveracceptsmailmessagesandforwardsthosetoarunningtestcaseforfurthervalidation.

NoteWehavenouserinboxwhereincomingmailsarestored.Themailserverjustforwardsincomingmailstotherunningtestforvalidation.Afterthetesttheincomingmailmessageisgone.

CitrusReferenceGuide

342Mail

Page 343: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

AndthisisexactlywhattheCitrusmailserveriscapableof.TheserverisaverylightweightSMTPserver.AllincomingmailclientconnectionsareacceptedbydefaultandthemaildataisconvertedintoaCitrusXMLmailinterfacerepresentation.TheXMLmailmessageisthenpassedtotherunningtestforvalidation.

LetushavealookattheCitrusmailservercomponentandhowyoucanaddittotheSpringapplicationcontext.

<citrus-mail:serverid="simpleMailServer"port="25025"auto-start="true"/>

Themailservercomponentreceivesseveralpropertiessuchasportorauto-start.CitrusstartsainmemorySMTPserverthatclientscanconnectto.

InyourtestcaseyoucanthenreceivetheincomingmailmessagesontheserverinordertoperformthewellknownXMLvalidationmechanismswithinCitrus.Themessageheaderandthepayloadcontainallmailinformationsoyoucanverifythecontentwithexpectedtemplatesasusual:

<receiveendpoint="simpleMailServer"><message><payload><mail-messagexmlns="http://www.citrusframework.org/schema/mail/message"><from>[email protected]</from><to>[email protected]</to><cc></cc><bcc></bcc><subject>Thisisatestmailmessage</subject><body><contentType>text/plain;charset=utf-8</contentType><content>HelloCitrusmailserver!</content></body></mail-message></payload><header><elementname="citrus_mail_from"value="[email protected]"/><elementname="citrus_mail_to"value="[email protected]"/><elementname="citrus_mail_subject"value="Thisisatestmailmessage"/><elementname="citrus_mail_content_type"value="text/plain;charset=utf-8"/></header></message></receive>

CitrusReferenceGuide

343Mail

Page 344: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Thegeneralmailpropertiessuchasfrom,to,subjectareavailableaselementsinthemailpayloadandinthemessageheaderinformation.ThemessageheadernamesdostartwithacommonCitrusmailprefixcitrus_mail.Followingfromthatyoucanverifythesespecialmailmessageheadersinyourtestasshownabove.Citrusoffersfollowingmailheaders:

citrus_mail_fromcitrus_mail_tocitrus_mail_cccitrus_mail_bcccitrus_mail_subjectcitrus_mail_replyTocitrus_mail_date

InadditiontothatCitrusconvertstheincomingmaildatatoaspecialXMLmailrepresentationwhichispassedasmessagepayloadtothetest.Themailbodypartsarerepresentedasbodyandoptionalattachmentelements.AsthisisplainXMLyoucanverifythemailmessagecontentasusualusingCitrusvariables,functionsandvalidationmatchers.

RegardlessofhowthemailmessagehaspassedthevalidationtheCitrusSMTPmailserverwillautomaticallyrespondwithsuccesscodes(SMTP250OK)tothecallingclient.ThisisthebasicCitrusmailserverbehaviorwhereallclientconnectionsareacceptedanallmailmessagesarerespondedwithSMTP250OKresponsecodes.

Nowinmoreadvancedusagescenariosthetestermaywanttocontrolthemailcommunicationoutcome.UsercanforcesomeerrorscenarioswheremailclientsarenotacceptedormailcommunicationshouldfailwithsomeSMTPerrorstateforinstance.

Byusingamoreadvancedmailserversetupthetestergetsmorepowertosendingbackmailserverresponsecodestothemailclient.Justusetheadvancedmailadapterimplementationinyourmailservercomponentconfiguration:

<citrus-mail:serverid="advancedMailServer"auto-accept="false"split-multipart="true"port="25025"auto-start="true"/>

CitrusReferenceGuide

344Mail

Page 345: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Wehavedisabledtheauto-acceptmodeonthemailserver.Thismeansthatwehavetodosomeadditionalstepsinyourtestcasetoaccepttheincomingmailmessagefirst.Sowecandecideinourtestcasewhethertoacceptordeclinetheincomingmailmessageforamorepowerfultest.Youaccept/declineamailmessagewithaspecialXMLacceptrequest/responseexchangeinyourtestcase:

<receiveendpoint="advancedMailServer"><message><payload><accept-requestxmlns="http://www.citrusframework.org/schema/mail/message"><from>[email protected]</from><to>[email protected]</to></accept-request></payload></message></receive>

Sobeforereceivingtheactualmailmessagewereceivethissimpleaccept-requestinourtest.Theacceptrequestgivesusthemessagefromandtoresourcesofthemailmessage.Nowthetestdecidestoalsodeclineamailclientconnection.Youcansimulatethattheserverdoesnotacceptthemailclientconnectionbysendingbackanegativeacceptresponse.

<sendendpoint="advancedMailServer"><message><payload><accept-responsexmlns="http://www.citrusframework.org/schema/mail/message"><accept>true</accept></accept-response></payload></message></send>

Dependingontheacceptoutcomethemailclientwillreceiveanerrorresponsewithpropererrorcodes.Ifyouacceptthemailmessagewithapositiveacceptresponsethenextstepinyourtestreceivestheactualmailmessageaswehaveseenitbeforeinthischapter.

Nowbesidesnotacceptingamailmessageinthefirstplaceyoucanalssimulateanothererrorscenariowiththemailserver.InthisscenariothemailservershouldrespondwithsomesortofSMTPerrorcodeafteracceptingthemessage.Thisisdonewithaspecialmailresponsemessagelikethis:

CitrusReferenceGuide

345Mail

Page 346: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<receiveendpoint="advancedMailServer"><message><payload><mail-messagexmlns="http://www.citrusframework.org/schema/mail/message"><from>[email protected]</from><to>[email protected]</to><cc></cc><bcc></bcc><subject>Thisisatestmailmessage</subject><body><contentType>text/plain;charset=utf-8</contentType><content>HelloCitrusmailserver!</content></body></mail-message></payload></message></receive>

<sendendpoint="advancedMailServer"><message><payload><mail-responsexmlns="http://www.citrusframework.org/schema/mail/message"><code>443</code><message>Failed!</message></mail-response></payload></message></send>

Asyoucanseefromtheexampleabovewefirstaccepttheconnectionandreceivethemailcontentasusual.Nowthetestreturnsanegativemailresponsewithsomeerrorcodereasonset.TheCitrusSMTPcommunicationwillthenfailandthecallingmailclientreceivestherespectiveerror.

IfyouskipthenegativemailresponsetheserverwillautomaticallyresponsewithpositiveSMTPresponsecodestothecallingclient.

CitrusReferenceGuide

346Mail

Page 347: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ArquilliansupportArquillianisawellknownintegrationtestframeworkthatcomeswithagreatfeaturesetwhenitcomestoJavaEEtestinginsideofafullqualifiedapplicationserver.WithArquiliianyoucandeployyourJavaEEservicesinarealapplicationserverofyourchoiceandexecutethetestsinsidetheapplicationserverboundaries.ThismakesitveryeasytotestyourJavaEEservicesinscopewithproperJNDIresourceallocationandotherresourcesprovidedbytheapplicationserver.CitrusisabletoconnectwiththeArquilliantestcase.SpeakinginmoredetailyourArquilliantestisabletouseaCitrusextensioninordertousetheCitrusfeaturesetinsidetheArquillianboundaries.

ReadthenextsectioninordertofindoutmoreabouttheCitrusArquillianextension.

CitrusArquillianextension

ArquillianoffersafinemechanismforextensionsaddingfeaturestotheArquilliantestsetupandtestexecution.TheCitrusextensionrespectivelyaddsCitrusframeworkinstancecreationandCitrustestexecutiontotheArquillianworld.Firstofallletshavealookattheextensiondescriptorpropertiessettableviaarquillian.xml:

<extensionqualifier="citrus"><propertyname="citrusVersion">2.7.1</property><propertyname="autoPackage">true</property><propertyname="suiteName">citrus-arquillian-suite</property></extension>

TheCitrusextensionusesaspecificqualifiercitrusfordefiningpropertiesinsidetheArquilliandescriptor.Followingpropertiesaresettableincurrentversion:

citrusVersion:TheexplicitversionofCitrusthatshouldbeused.Besuretohavethesamelibraryversionavailableinyourproject(e.g.asMavendependency).Thispropertyisoptional.

Bydefaulttheextensionjustusesthelateststableversion.

autoPackage:Whentrue(defaultsetting)theextensionwillautomaticallyaddCitruslibrariesandalltransitivedependenciestothetestdeployment.ThisautomaticallyenablesyoutousetheCitrusAPIinsidetheArquilliantest

evenwhenthetestisexecutedinsidetheapplicationcontainer.

CitrusReferenceGuide

347Arquillian

Page 348: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

suiteName:ThisoptionalsettingdefinesthenameofthetestsuitethatisusedfortheCitrustestrun.Whenusingbefore/aftersuitefunctionalityinCitrusthissettingmightbeofinterest.configurationClass:FullqualifiedJavaclassnameofcustomizedCitrusSpringbeanconfigurationtousewhenloadingtheCitrusSpringapplicationcontext.Asauseryoucandefineacustomconfigurationclassthatmust

beasubclassofcom.consol.citrus.config.CitrusSpringConfig.Whenspecifiedthecustomclassisloadedotherwisethedefaultcom.consol.citrus.config.CitrusSpringConfigisloadedtosetuptheSpringapplicationcontext.

NowthatwehaveaddedtheextensiondescriptorwithallpropertiesweneedtoaddtherespectiveCitrusArquillianextensionaslibrarytoourproject.ThisisdoneviaMaveninyourproject'sPOMfileasnormaldependency:

<dependency><groupId>com.consol.citrus</groupId><artifactId>citrus-arquillian</artifactId><version>2.7.1</version><scope>test</scope></dependency>

NoweverythingissetuptouseCitruswithinArquillian.LetsuseCitrusfunctionalityinaArquilliantestcase.

Clientsidetesting

Arquillianseparatesclientandcontainersidetesting.Whenusingclientsidetestingthetestcaseisexecutedoutsideoftheapplicationcontainerdeployment.ThismeansthatyourtestcasehasnodirectaccesstocontainermanagedresourcessuchasJNDIresources.Ontheplussideitisnotnecessarytoincludeyourtestinthecontainerdeployment.Thetestcaseinteractswiththecontainerdeploymentasanormalclientwoulddo.Letshavealookatafirstexample:

@RunWith(Arquillian.class)@RunAsClientpublicclassEmployeeResourceTest

@CitrusFrameworkprivateCitruscitrusFramework;

CitrusReferenceGuide

348Arquillian

Page 349: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

@ArquillianResourceprivateURLbaseUri;

privateStringserviceUri;

@DeploymentpublicstaticWebArchivecreateDeployment()returnShrinkWrap.create(WebArchive.class).addClasses(RegistryApplication.class,EmployeeResource.class,Employees.class,Employee.class,EmployeeRepository.class);

@BeforepublicvoidsetUp()throwsMalformedURLExceptionserviceUri=newURL(baseUri,"registry/employee").toExternalForm();

@Test@CitrusTestpublicvoidtestCreateEmployeeAndGet(@CitrusResourceTestDesignerdesigner)designer.send(serviceUri).message(newHttpMessage("name=Penny&age=20").method(HttpMethod.POST).contentType(MediaType.APPLICATION_FORM_URLENCODED));

designer.receive(serviceUri).message(newHttpMessage().statusCode(HttpStatus.NO_CONTENT));

designer.send(serviceUri).message(newHttpMessage().method(HttpMethod.GET).accept(MediaType.APPLICATION_XML));

designer.receive(serviceUri).message(newHttpMessage(""+""+"20"+"Penny"+""+"").statusCode(HttpStatus.OK));

citrusFramework.run(designer.build());

FirstofallweusethebasicArquillianJUnittestrunner@RunWith(Arquillian.class)incombinationwiththe@RunAsClientannotationtellingArquillianthatthisisaclientsidetestcase.AsthisisausualArquilliantestcasewehaveaccesstoArquillianresources

CitrusReferenceGuide

349Arquillian

Page 350: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

thatautomaticallygetinjectedsuchasthebaseuriofthetestdeployment.ThetestdeploymentisawebdeploymentcreatedviaShrinkWrap.WeaddtheapplicationspecificclassesthatbuildourremoteRESTfulservicethatwewouldliketotest.

TheCitrusArquillianextensionisabletosetupaproperCitrustestenvironmentinthebackground.AsaresultthetestcasecanreferenceaCitrusframeworkinstancewiththe@CitrusFrameworkannotation.WewillusethisinstanceofCitruslateronwhenitcomestoexecutetheCitrustestinglogic.

NowecanfocusonwritingatestmethodwhichisagainnothingbutanormalJUnittestmethod.TheCitrusextensiontakescareoninjectingthe@CitrusResourceannotatedmethodparameter.WiththisCitrustestdesignerinstancewecanbuildaCitrustestlogicforsendingandreceivingmessagesviaHttpinordertocalltheremoteRESTfulemployeeserviceofourtestdeployment.TheHttpendpointuriisinjectedviaArquillianandweareabletocalltheremoteserviceasaclient.

TheCitrustestdesignerprovidesJavaDSLmethodsforbuildingthetestlogic.Pleasenotethatthedesignerwillaggregateallactionssuchassendorreceiveuntilthedesigneriscalledtobuildthetestcasewithbuild()methodinvocation.TheresultingtestcaseobjectcanbeexecutedbytheCitrusframeworkinstancewithrun()method.

WhentheCitrustestcaseisexecutedthemessagesaresentoverthewire.TherespectiveresponsemessageisreceivedwithwellknownCitrusreceivemessagelogic.Wecanvalidatetheresponsemessagesaccordinglyandmakesuretheclientcallwasdoneright.IncasesomethinggoeswrongwithinCitrustestexecutiontheframeworkwillraiseexceptionsaccordingly.AsaresulttheJUnittestmethodissuccessfulorfailedwitherrorscomingfromCitrustestexecution.

ThisishowCitrusandArquilliancaninteractinatestscenariowherethetestdeploymentismanagedbyArquillianandtheclientsideactionstakeplacewithinCitrus.ThisisagreatwaytocombinebothframeworkswithCitrusbeingabletocalldifferentserviceAPIendpointsinadditionwithvalidatingtheoutcome.Thiswasaclientsidetestcasewherethetestlogicwasexecutedoutsideoftheapplicationcontainer.Arquillianalsosupportscontainerremotetestcaseswherewehavedirectaccesstocontainermanagedresources.ThefollowingsectiondescribeshowthisworkswithCitrus.

Containersidetesting

InprevioussectionswehaveseenhowtocombineCitruswithArquillianinaclientsidetestcase.Thisisthewaytogoforalltestcasesthatdonotneedtohaveaccessoncontainermanagedresources.Letshavealookatasamplewherewewanttogain

CitrusReferenceGuide

350Arquillian

Page 351: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

accesstoaJMSqueueandconnectionmanagedbytheapplicationcontainer.

@RunWith(Arquillian.class)publicclassEchoServiceTest

@CitrusFrameworkprivateCitruscitrusFramework;

@Resource(mappedName="jms/queue/test")privateQueueechoQueue;

@Resource(mappedName="/ConnectionFactory")privateConnectionFactoryconnectionFactory;

privateJmsSyncEndpointjmsSyncEndpoint;

@Deployment@OverProtocol("Servlet3.0")publicstaticWebArchivecreateDeployment()throwsMalformedURLExceptionreturnShrinkWrap.create(WebArchive.class).addClasses(EchoService.class);

@BeforepublicvoidsetUp()JmsSyncEndpointConfigurationendpointConfiguration=newJmsSyncEndpointConfiguration();endpointConfiguration.setConnectionFactory(newSingleConnectionFactory(connectionFactory));endpointConfiguration.setDestination(echoQueue);jmsSyncEndpoint=newJmsSyncEndpoint(endpointConfiguration);

@AfterpublicvoidcleanUp()closeConnections();

@Test@CitrusTestpublicvoidshouldBeAbleToSendMessage(@CitrusResourceTestDesignerdesigner)throwsExceptionStringmessageBody="ping";

designer.send(jmsSyncEndpoint).messageType(MessageType.PLAINTEXT).message(newJmsMessage(messageBody));

designer.receive(jmsSyncEndpoint).messageType(MessageType.PLAINTEXT).message(newJmsMessage(messageBody));

citrusFramework.run(designer.build());

CitrusReferenceGuide

351Arquillian

Page 352: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

privatevoidcloseConnections()((SingleConnectionFactory)jmsSyncEndpoint.getEndpointConfiguration().getConnectionFactory()).destroy();

AsyoucanseethetestcaseaccessestwocontainermanagedresourcesviaJNDI.ThisisaJMSqueueandaJMSconnectionthatgetautomaticallyinjectedasresources.InabeforetestannotatedmethodwecanusetheseresourcestobuildupaproperCitrusJMSendpoint.InsidethetestmethodwecanusetheJMSendpointforsendingandreceivingJMSmessagesviaCitrus.Asusualresponsemessagesreceivedarevalidatedandcomparedtoanexpectedmessage.AsusualweusetheCitrusTestDesignermethodparameterthatisinjectedbytheframework.ThedesignerisabletobuildCitrustestlogicwithJavaDSLmethods.Oncethecompletetestisdesignedwecanbuildthetestcaseandrunthetestcasewiththeframeworkinstance.AfterthetestweshouldclosetheJMSconnectioninordertoavoidexceptionswhentheapplicationcontainerisshuttingdownafterthetest.

Thetestisnowpartofthetestdeploymentandisexecutedwithintheapplicationcontainerboundaries.AsusualwecanusetheCitrusextensiontoautomaticallyinjecttheCitrusframeworkinstanceaswellastheCitrustestbuilderinstanceforbuildingtheCitrustestlogic.

ThisishowtocombineCitrusandArquillianinordertobuildintegrationtestsonJavaEEservicesinarealapplicationcontainerenvironment.WithCitrusyouareabletosetupmorecomplextestscenarioswithsimulatedservicessuchasmailorftpservers.WecanbuildCitrusendpointswithcontainermanagedresources.

Testrunners

IntheprevioussectionswehaveusedtheCitrusTestDesignerinordertoconstructaCitrustestcasetoexecutewithintheArquillianboundaries.ThenatureofthetestdesigneristoaggregateallJavaDSLmethodcallsinordertobuildacompleteCitrustestcasebeforeexecutionisdoneviatheCitrusframework.ThisapproachcancausesomeunexpectedbehaviorwhenmixingtheCitrusJavaDSLmethodcallswithArquilliantestlogic.LetsdescribethisbyhavingalookatanexamplewherethmixtureoftestdesignerandpureJavatestlogiccausesunseenproblems.

@Test@CitrusTest

CitrusReferenceGuide

352Arquillian

Page 353: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

publicvoidtestDesignRuntimeMixture(@CitrusResourceTestDesignerdesigner)throwsExceptiondesigner.send(serviceUri).message(newHttpMessage("name=Penny&age=20").method(HttpMethod.POST).contentType(MediaType.APPLICATION_FORM_URLENCODED));

designer.receive(serviceUri).message(newHttpMessage()).statusCode(HttpStatus.NO_CONTENT));

EmployeetestEmployee=employeeService.findEmployee("Penny");employeeService.addJob(testEmployee,"waitress");

designer.send(serviceUri).message(newHttpMessage().method(HttpMethod.GET).accept(MediaType.APPLICATION_XML));

designer.receive(serviceUri).message(newHttpMessage(""+""+"20"+"Penny"+""+"waitress"+""+""+"")).statusCode(HttpStatus.OK));

citrusFramework.run(designer.build());

AsyoucanseeinthisexamplewecreateanewEmployeenamedPennyviatheHttpRESTAPIonourservice.WedothiswithCitrusHttpsendandreceivemessagelogic.Oncethisisdonewewouldliketoaddajobdescriptiontotheemployee.WeuseaserviceinstanceofEmployeeServicewhichisaserviceofourtestdomainthatisinjectedtotheArquilliantestascontainerJEEresource.Firstofallwefindtheemployeeobjectandthenweaddsomejobdescriptionusingtheservice.NowasaresultwewouldliketoreceivetheemployeeasXMLrepresentationviaaRESTservicecallwithCitrusandweexpectthejobdescriptiontobepresent.

ThiscombinationofCitrusJavaDSLmethodsandservicecalllogicwillnotworkwithTestDesigner.ThisisbecausetheCitrustestlogicisnotexecutedimmediatelybutaggregatedtotheveryendwherethedesigneriscalledtobuildthetestcase.ThecombinationofCitrusdesigntimeandJavatestruntimeistricky.

CitrusReferenceGuide

353Arquillian

Page 354: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

FortunatelywehavesolvedthisissuewithprovidingaseparateTestRunnercomponent.ThetestrunnerprovidesnearlythesameJavaDSLmethodsforconstructingCitrustestlogicasthetestdesigner.ThedifferencethoughisthatthetestlogicisexecutedimmediatelywhencallingtheJavaDSLmethods.SofollowingfromthatwecanmixCitrusJavaDSLcodewithtestruntimelogicasexpected.Seehowthislookslikewithourexample:

@Test@CitrusTestpublicvoidtestDesignRuntimeMixture(@CitrusResourceTestRunnerrunner)throwsExceptionrunner.send(builder->builder.endpoint(serviceUri).message(newHttpMessage("name=Penny&age=20").method(HttpMethod.POST).contentType(MediaType.APPLICATION_FORM_URLENCODED)));

runner.receive(builder->builder.endpoint(serviceUri).message(newHttpMessage().statusCode(HttpStatus.NO_CONTENT)));

EmployeetestEmployee=employeeService.findEmployee("Penny");employeeService.addJob(testEmployee,"waitress");

runner.send(builder->builder.endpoint(serviceUri).message(newHttpMessage().method(HttpMethod.GET).accept(MediaType.APPLICATION_XML)));

runner.receive(builder->builder.endpoint(serviceUri).message(newHttpMessage(""+""+"20"+"Penny"+""+"waitress"+""+""+"").statusCode(HttpStatus.OK)));

Thetestlogichasnotchangedsignificantly.WeusetheCitrusTestRunnerasmethodinjectedparameterinsteadoftheTestDesigner.Andthisisprettymuchthetrick.NowtheJavaDSLmethodsdoexecutetheCitrustestlogicimmediately.ThisiswhythesyntaxoftheCitrusJavaDSLmethodshavechangedalittlebit.Wenowusea

CitrusReferenceGuide

354Arquillian

Page 355: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

anonymousinterfaceimplementationforconstructingthesend/receivetestactionlogic.AsaresultwecanusetheCitrusJavaDSLasnormalcodeandwecanmixtheruntimeJavalogicaseachstatementisexecutedimmediately.

WithJava8lambdaexpressionsourcodelooksevenmorestraightforwardandlessverboseaswecanskiptheanonymousinterfaceimplementations.WithJava8youcanwritethesametestlikethis:

@Test@CitrusTestpublicvoidtestDesignRuntimeMixture(@CitrusResourceTestRunnerrunner)throwsExceptionrunner.send(builder->builder.endpoint(serviceUri).message(newHttpMessage("name=Penny&age=20").method(HttpMethod.POST).contentType(MediaType.APPLICATION_FORM_URLENCODED));

runner.receive(builder->builder.endpoint(serviceUri).message(newHttpMessage().statusCode(HttpStatus.NO_CONTENT));

EmployeetestEmployee=employeeService.findEmployee("Penny");employeeService.addJob(testEmployee,"waitress");

runner.send(builder->builder.endpoint(serviceUri).message(newHttpMessage().method(HttpMethod.GET).accept(MediaType.APPLICATION_XML));

runner.receive(builder->builder.endpoint(serviceUri).message(newHttpMessage(""+""+"20"+"Penny"+""+"waitress"+""+""+"").statusCode(HttpStatus.OK));

CitrusReferenceGuide

355Arquillian

Page 356: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

DockersupportCitrusprovidesconfigurationcomponentsandtestactionsforinteractionwithaDockerdaemon.TheCitrusdockerclientcomponentwillexecuteDockercommandsforcontainermanagementsuchasstart,stop,build,inspectandsoon.TheDockerclientbydefaultusestheDockerremoteRESTAPI.AsauseryoucanexecuteDockercommandsaspartofaCitrustestandvalidatepossiblecommandresults.

NoteTheDockertestcomponentsinCitrusarekeptinaseparateMavenmodule.IfnotalreadydonesoyouhavetoincludethemoduleasMavendependencytoyourproject

<dependency><groupId>com.consol.citrus</groupId><artifactId>citrus-docker</artifactId><version>2.7.1</version></dependency>

Citrusprovidesa"citrus-docker"configurationnamespaceandschemadefinitionforDockerrelatedcomponentsandactions.IncludethisnamespaceintoyourSpringconfigurationinordertousetheCitrusDockerconfigurationelements.ThenamespaceURIandschemalocationareaddedtotheSpringconfigurationXMLfileasfollows.

<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:citrus-docker="http://www.citrusframework.org/schema/docker/config"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/docker/confighttp://www.citrusframework.org/schema/docker/config/citrus-docker-config.xsd">

[...]

</beans>

AfterthatyouareabletousecustomizedCitrusXMLelementsinordertodefinetheSpringbeans.

Dockerclient

CitrusReferenceGuide

356Docker

Page 357: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

CitrusoperateswiththeDockerremoteRESTAPIinordertointeractwiththeDockerdaemon.TheDockerclientisdefinedasSpringbeancomponentintheconfigurationasfollows:

<citrus-docker:clientid="dockerClient"/>

TheDockerclientcomponentaboveisusingalldefaultconfigurationvalues.BydefaultCitrusissearchingthesystempropertiesaswellasenvironmentvariablesfordefaultDockersettingssuchas:

DOCKER_HOST="tcp://localhost:2376"DOCKER_CERT_PATH="~/.docker/machine/machines/default"DOCKER_TLS_VERIFY="1"DOCKER_MACHINE_NAME="default"

IncasethesesettingsarenotsettableinyourenvironmentyoucanalsouseexplicitsettingsintheDockerclientcomponent:

<citrus-docker:clientid="dockerClient"url="tcp://localhost:2376"version="1.20"username="user"password="s!cr!t"email="[email protected]"registry="https://index.docker.io/v1/"cert-path="/path/to/some/cert/directory"config-path="/path/to/some/config/directory"/>

NowCitrusisabletoaccesstheDockerremoteAPIforexecutingcommandssuchasstart,stop,build,inspectandsoon.

Dockercommands

WehaveseveralCitrustestactionseachrepresentingaDockercommand.TheseactionscanbepartofatestcasewhereyoucanmanageDockercontainersinsidethetest.AsaprerequisitewehavetoenabletheDockerspecifictestactionsinourXMLtestasfollows:

<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:docker="http://www.citrusframework.org/schema/docker/testcase"xsi:schemaLocation="

CitrusReferenceGuide

357Docker

Page 358: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/docker/testcasehttp://www.citrusframework.org/schema/docker/testcase/citrus-docker-testcase.xsd">

[...]

</beans>

Weaddedaspecialdockernamespacewithprefixdocker:sonowwecanstarttoaddDockertestactionstothetestcase:

XMLDSL

<testcasename="DockerCommandIT"><actions><docker:ping></docker:ping>

<docker:version><docker:expect><docker:result><![CDATA["Version":"1.8.3","ApiVersion":"1.21","GitCommit":"@ignore@","GoVersion":"go1.4.2","Os":"darwin","Arch":"amd64","KernelVersion":"@ignore@"]]></docker:result></docker:expect></docker:version></actions></testcase>

InthisverysimpleexamplewefirstpingtheDockerdaemontomakesurewehaveconnectivityupandrunning.AfterthatwegettheDockerversioninformation.ThesecondactionshowsanimportantconceptwhenexecutingDockercommandsinCitrus.Asatesterwemightbeinterestedinvalidatingthecommandresult.Sowencanspecifyanoptionaldocker:resultwhichisusuallyinJSONdataformat.AsusualwecanusetestvariableshereandignoresomevaluesexplicitlysuchastheGitCommitvalue.

BasedonthatwecanexecuteseveralDockercommandsinatestcase:

CitrusReferenceGuide

358Docker

Page 359: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

XMLDSL

<testcasename="DockerCommandIT"><variables><variablename="imageId"value="busybox"></variable><variablename="containerName"value="citrus_box"></variable></variables>

<actions><docker:pullimage="$imageId"tag="latest"/>

<docker:createimage="$imageId"name="$containerName"cmd="top"><docker:expect><docker:result><![CDATA["Id":"@variable(containerId)@","Warnings":null]]></docker:result></docker:expect></docker:create>

<docker:startcontainer="$containerName"/></actions></testcase>

InthisexamplewepullaDockerimage,buildanewcontaineroutofthisimageandstartthecontainer.AsyoucanseeeachDockercommandactionoffersattributessuchascontainer,imageortag.ThesearecommandsettingsthatareavailableontheDockercommandspecification.ReadmoreabouttheDockercommandsandthespecificsettingsinofficialDockerAPIreferenceguide.

CitrussupportsthefollowingDockercommandswithrespectivetestactions:

docker:pulldocker:builddocker:createdocker:startdocker:stopdocker:waitdocker:pingdocker:versiondocker:inspect

CitrusReferenceGuide

359Docker

Page 360: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

docker:removedocker:info

SomeoftheDockercommandscanbeexecutedbothoncontainerandimagetargetssuchasdocker:inspectordocker:remove.Thecommandactionthenoffersbothcontainerandimageattributessotheusercanchoosethetargetofthecommandoperationtobeacontaineroranimage.

UptonowwehaveonlyusedtheCitrusXMLDSL.OfcourseallDockercommandsarealsoavailableinJavaDSLasthenextexampleshows.

JavaDSL

@CitrusTestpublicvoiddockerTest()docker().version().validateCommandResult(newCommandResultCallback<Version>()@OverridepublicvoiddoWithCommandResult(Versionversion,TestContextcontext)Assert.assertEquals(version.getApiVersion(),"1.20"););

docker().ping();

docker().start("my_container");

TheJavaDSLDockercommandsprovideanoptionalCommandResultCallbackthatiscalledwiththeunmarshalledcommandresultobject.IntheexampleabovetheVersionmodelobjectispassedasargumenttothecallback.Sothetestercanaccessthecommandresultandvalidateitspropertieswithassertions.

BydefaultCitrustriestofindaDockerclientcomponentwithintheCitrusSpringapplicationcontext.IfnotpresentCitruswillinstantiateadefaultdockerclientwithalldefaultsettings.YoucanalsoexplicitlysetthedockerclientinstancewhenusingtheJavaDSLDockercommandactions:

JavaDSL

@AutowiredprivateDockerClientdockerClient;

@CitrusTestpublicvoiddockerTest()

CitrusReferenceGuide

360Docker

Page 361: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

docker().client(dockerClient).version().validateCommandResult(newCommandResultCallback<Version>()@OverridepublicvoiddoWithCommandResult(Versionversion,TestContextcontext)Assert.assertEquals(version.getApiVersion(),"1.20"););

docker().client(dockerClient).ping();

docker().client(dockerClient).start("my_container");

CitrusReferenceGuide

361Docker

Page 362: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

KubernetessupportKubernetesisoneofthehottestmanagementplatformsforcontainerizedapplicationsthesedays.Kubernetesletsyoudeploy,scaleandmanageyourcontainersontheplatformsoyougetfeatureslikeauto-scaling,self-healing,servicediscoveryandloadbalancing.CitrusprovidesinteractionwiththeKubernetesRESTAPIsoyoucanaccesstheKubernetesplatformanditsresourceswithinaCitrustestcase.

NoteTheKubernetestestcomponentsinCitrusarekeptinaseparateMavenmodule.IfnotalreadydonesoyouhavetoincludethemoduleasMavendependencytoyourproject

<dependency><groupId>com.consol.citrus</groupId><artifactId>citrus-kubernetes</artifactId><version>2.7.1</version></dependency>

Citrusprovidesa"citrus-kubernetes"configurationnamespaceandschemadefinitionforKubernetesrelatedcomponentsandactions.IncludethisnamespaceintoyourSpringconfigurationinordertousetheCitrusKubernetesconfigurationelements.ThenamespaceURIandschemalocationareaddedtotheSpringconfigurationXMLfileasfollows.

<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:citrus-k8s="http://www.citrusframework.org/schema/kubernetes/config"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/kubernetes/confighttp://www.citrusframework.org/schema/kubernetes/config/citrus-kubernetes-config.xsd">

[...]

</beans>

AfterthatyouareabletousecustomizedCitrusXMLelementsinordertodefinetheSpringbeans.

CitrusReferenceGuide

362Kubernetes

Page 363: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Kubernetesclient

CitrusoperateswiththeKubernetesremoteRESTAPIinordertointeractwiththeKubernetesplatform.TheKubernetesclientisdefinedasSpringbeancomponentintheconfigurationasfollows:

<citrus-k8s:clientid="myK8sClient"/>

TheKubernetesclientisbasedontheFabric8JavaKubernetesclientimplementation.Followingfromthatthecomponentcanbeconfiguredinvariousways.BydefaulttheclientreadsthesystempropertiesaswellasenvironmentvariablesfordefaultKubernetessettingssuchas:

kubernetes.master/KUBERNETES_MASTERkubernetes.api.version/KUBERNETES_API_VERSIONkubernetes.trust.certificates/KUBERNETES_TRUST_CERTIFICATES

Ifyousetthesepropertiesinyourenvironmenttheclientcomponentwillautomaticallypickuptheconfigurationsettings.Alsowhenusingkubectlcommandlinelocallytheclientmayautomaticallyusethestoreduserauthenticationsettingsfromthere.ForacompletelistofsettingsandexplanationofthosepleaserefertotheFabric8clientdocumentation.

IncaseyouneedtosettheclientconfigurationexplicitlyonyourenvironmentyoucanalsouseexplicitsettingsontheKubernetesclientcomponent:

<citrus-k8s:clientid="myK8sClient"url="http://localhost:8843"version="v1"username="user"password="s!cr!t"namespace="user_namespace"message-converter="messageConverter"object-mapper="objectMapper"/>

NowCitrusisabletoaccesstheKubernetesremoteAPIforexecutingcommandssuchaslist-pods,watch-servicesandsoon.CitrusprovidesasetofactionsthatperformaKubernetescommandviaREST.TheresultsusuallygetvalidatedintheCitrustestasusual.

BasedonthatwecanexecuteseveralKubernetescommandsinatestcaseandvalidatetheJsonresults:

CitrusReferenceGuide

363Kubernetes

Page 364: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

CitrussupportsthefollowingKubernetesAPIcommandswithrespectivetestactions:

k8s:infok8s:list-podsk8s:get-podk8s:delete-podk8s:list-servicesk8s:get-servicek8s:delete-servicek8s:list-namespacesk8s:list-eventsk8s:list-endpointsk8s:list-nodesk8s:list-replication-controllersk8s:watch-podsk8s:watch-servicesk8s:watch-namespacesk8s:watch-nodesk8s:watch-replication-controllers

Wewilldiscussthesecommandsindetaillateroninthischapter.FornowletshaveacloserlookonhowtousethecommandsinsideofaCitrustest.

KubernetescommandsinXML

WehaveseveralCitrustestactionseachrepresentingaKubernetescommand.TheseactionscanbepartofatestcasewhereyoucanmanageKubernetespodsinsidethetest.AsaprerequisitewehavetoenabletheKubernetesspecifictestactionsinourXMLtestasfollows:

<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:k8s="http://www.citrusframework.org/schema/kubernetes/testcase"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/kubernetes/testcasehttp://www.citrusframework.org/schema/kubernetes/testcase/citrus-kubernetes-testcase.xsd"

[...]

</beans>

CitrusReferenceGuide

364Kubernetes

Page 365: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Weaddedaspecialkubernetesnamespacewithprefixk8s:sonowwecanstarttoaddKubernetestestactionstothetestcase:

XMLDSL

<testcasename="KubernetesCommandIT"><actions><k8s:infoclient="myK8sClient"><k8s:validate><k8s:result>"result":"clientVersion":"1.4.27","apiVersion":"v1","kind":"Info","masterUrl":"$masterUrl","namespace":"test"</k8s:result></k8s:validate></k8s:info>

<k8s:list-pods><k8s:validate><k8s:result>"result":"apiVersion":"v1","kind":"PodList","metadata":"@ignore@","items":[]</k8s:result><k8s:elementpath="$.result.items.size()"value="0"/></k8s:validate></k8s:list-pods></actions></testcase>

InthisverysimpleexamplewefirstpingtheKubernetesRESTAPItomakesurewehaveconnectivityupandrunning.TheinfocommandconnectstheRESTAPIandreturnsalistofstatusinformationoftheKubernetesclient.AfterthatwegetthelistofavailableKubernetespods.Asatesterwemightbeinterestedinvalidatingthecommandresults.Sowencanspecifyanoptionalk8s:resultwhichisusuallyinJsonformat.WiththatwecanapplythefullCitrusJsonvalidationpowertotheKubernetes

CitrusReferenceGuide

365Kubernetes

Page 366: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

results.Asusualwecanusetestvariableshereandignoresomevaluesexplicitlysuchasthemetadatavalue.AlsoJsonPathexpressionvalidationandJsontestmessagevalidationfeaturesinCitruscomeinheretovalidatetheresults.

KubernetescommandsinJava

UptonowwehaveonlyusedtheCitrusXMLDSL.OfcourseallKubernetescommandsarealsoavailableinJavaDSLasthenextexampleshows.

JavaDSL

@CitrusTestpublicvoidkubernetesTest()kubernetes().info().validate(newCommandResultCallback<InfoResult>()@OverridepublicvoiddoWithCommandResult(InfoResultinfo,TestContextcontext)Assert.assertEquals(info.getApiVersion(),"v1"););

kubernetes().pods().list().withoutLabel("running").label("app","myApp");

TheJavaDSLKubernetescommandsprovideanoptionalCommandResultCallbackthatisautomaticallycalledwiththeunmarshalledcommandresultobject.IntheexampleabovetheInfoResultmodelobjectispassedasargumenttothecallback.Sothetestercanaccessthecommandresultandvalidateitspropertieswithassertions.

Java8Lambdaexpressionsaddsomesyntacticalsugartothecommandresultvalidation:

JavaDSL

@CitrusTestpublicvoidkubernetesTest()kubernetes().info().validate((info,context)->Assert.assertEquals(info.getApiVersion(),"v1"));

kubernetes().pods().list()

CitrusReferenceGuide

366Kubernetes

Page 367: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

.withoutLabel("running").label("app","myApp");

BydefaultCitrustriestofindaKubernetesclientcomponentwithintheCitrusSpringapplicationcontext.IfnotpresentCitruswillinstantiateadefaultkubernetesclientwithalldefaultsettings.YoucanalsoexplicitlysetthekubernetesclientinstancewhenusingtheJavaDSLKubernetescommandactions:

JavaDSL

@AutowiredprivateKubernetesClientkubernetesClient;

@CitrusTestpublicvoidkubernetesTest()kubernetes().client(kubernetesClient).info().validate((info,context)->Assert.assertEquals(info.getApiVersion(),"v1"));

kubernetes().client(kubernetesClient).pods().list().withoutLabel("running").label("app","myApp");

Infocommand

TheinfocommandjustgetstheclientconnectionsettingsandprovidesthemasaJsonresulttotheaction.

XMLDSL

<k8s:infoclient="myK8sClient"><k8s:validate><k8s:result>"result":"clientVersion":"1.4.27","apiVersion":"v1","kind":"Info","masterUrl":"$masterUrl","namespace":"test"

CitrusReferenceGuide

367Kubernetes

Page 368: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</k8s:result></k8s:validate></k8s:info>

JavaDSL

@CitrusTestpublicvoidinfoTest()kubernetes().info().validate((info,context)->Assert.assertEquals(info.getApiVersion(),"v1"));

Listresources

WecanlistKubernetesresourcessuchaspods,services,endpointsandreplicationcontrollers.Thelistcanbefilteredbyseveralpropertiessuchas

labelnamespace

Thetestactionisabletodefinerespectivefilterstothelistsowegetonlypodsthematchthegivenattributes:

XMLDSL

<k8s:list-podslabel="app=todo"><k8s:validate><k8s:result>"result":"apiVersion":"$apiVersion","kind":"PodList","metadata":"@ignore@","items":"@ignore@"</k8s:result><k8s:elementpath="$.result.items.size()"value="1"/><k8s:elementpath="$..status.phase"value="Running"/></k8s:validate></k8s:list-pods>

JavaDSL

@CitrusTestpublicvoidlistPodsTest()

CitrusReferenceGuide

368Kubernetes

Page 369: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

kubernetes().client(k8sClient).pods().list().label("app=todo").validate("$..status.phase","Running").validate((pods,context)->Assert.assertFalse(CollectionUtils.isEmpty(pods.getResult().getItems())););

Asyoucanseeweareabletogivethepodlabelthatissearchedforinlistofallpods.ThelistreturnedisvalidatedeitherbygivinganexpectedJsonmessageorbyaddingJsonPathexpressionswithexpectedvaluestocheck.

InJavaDSLwecanaddavalidationresultcallbackthatisprovidedwiththeunmarshalledresultobjectforvalidation.Besideslabelfilteringwecanalsospecifythenamespaceandthepodnametosearchfor.

Youcanalsodefinemultiplelabelsascommadelimitedlist:

<k8s:list-serviceslabel="stage!=test,provider=fabric8"namespace="default"/>

Asyoucanseewehavecombinedtolabelfiltersstage!=testandprovider=fabric8onpodsinnamespacedefault.Thefirstlabelfilterisnegatedsothelabelstageshouldnotbetesthere.

Listnodesandnamespaces

Nodesandnamespacesarespecialresourcesthatarenotfilteredbytheirnamespaceastheyaremoreglobalresources.Therestisprettysimilartolistingpodsorservices.Wecanaddfilteressuchasnameandlabel.

XMLDSL

<k8s:list-namespaceslabel="provider=citrus"><k8s:validate><k8s:elementpath="$.result.items.size()"value="1"/></k8s:validate></k8s:list-namespaces>

JavaDSL

CitrusReferenceGuide

369Kubernetes

Page 370: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

@CitrusTestpublicvoidlistPodsTest()kubernetes().client(k8sClient).namespaces().list().label("provider=citrus").validate((pods,context)->Assert.assertFalse(CollectionUtils.isEmpty(pods.getResult().getItems())););

Getresources

WecangetaveryspecialKubernetesresourcesuchasapodorservicefordetailedvalidationofthatresource.WeneedtospecifyaresourcenameinordertoselecttheresourcefromlistofavailableresourcesinKubernetes.

XMLDSL

<k8s:get-podname="citrus_pod"><k8s:validate><k8s:result>"result":"apiVersion":"$apiVersion","kind":"Pod","metadata":"annotations":"@ignore@","creationTimestamp":"@ignore@","finalizers":[],"generateName":"@startsWith('hello-minikube-')@","labels":"pod-template-hash":"@ignore@","run":"hello-minikube","name":"$podName","namespace":"default","ownerReferences":"@ignore@","resourceVersion":"@ignore@","selfLink":"/api/$apiVersion/namespaces/default/pods/$podName","uid":"@ignore@","spec":"containers":["args":[],"command":[],"env":[],"image":"gcr.io/google_containers/echoserver:1.4",

CitrusReferenceGuide

370Kubernetes

Page 371: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

"imagePullPolicy":"IfNotPresent","name":"hello-minikube","ports":["containerPort":8080,"protocol":"TCP"],"resources":,"terminationMessagePath":"/dev/termination-log","volumeMounts":"@ignore@"],"dnsPolicy":"ClusterFirst","imagePullSecrets":"@ignore@","nodeName":"minikube","restartPolicy":"Always","securityContext":"@ignore@","serviceAccount":"default","serviceAccountName":"default","terminationGracePeriodSeconds":30,"volumes":"@ignore@","status":"@ignore@"</k8s:result><k8s:elementpath="$..status.phase"value="Running"/></k8s:validate></k8s:get-pod>

JavaDSL

@CitrusTestpublicvoidgetPodsTest()kubernetes().client(k8sClient).pods().get("citrus_pod").validate("$..status.phase","Running").validate((pod,context)->Assert.assertEquals(pods.getResult().getStatus().getPhase(),"Running"););

AsyoucanseeweareablegetthecompletepodinformationfromKubernetes.TheresultisvalidatedwithJsonmessagevalidatorinCitrus.Thismeanswecanuse@ignore@aswellastestvariablesandJsonPathexpressions.

Createresources

CitrusReferenceGuide

371Kubernetes

Page 372: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

WecancreatenewKubernetesresourceswithinaCitrustest.Thisisveryimportantincaseweneedtosetupnewpodsorservicesforthetestrun.Youcancreatenewresourcesbygivinga.ymlfileholdingallinformationhowtocreatethenewresource.SeethefollowingsampleYAMLforanewpodandservice:

kind:PodapiVersion:v1metadata:name:hello-jetty-$randomIdnamespace:defaultselfLink:/api/v1/namespaces/default/pods/hello-jetty-$randomIduid:citrus:randomUUID()labels:server:hello-jettyspec:containers:-name:hello-jettyimage:jetty:9.3imagePullPolicy:IfNotPresentports:-containerPort:8080protocol:TCPrestartPolicy:AlwaysterminationGracePeriodSeconds:30dnsPolicy:ClusterFirstserviceAccountName:defaultserviceAccount:defaultnodeName:minikube

ThisYAMLfilespecifiesanewresourceofkindPod.Wedefinethemetadataaswellasallcontainersthatarepartofthispod.Thecontainerisbuildfromjetty:9.3DockerimagethatshouldbepulledautomaticallyfromDockerHubregistry.Wealsoexposeport8080ascontainerPortsotheupcomingserviceconfigurationcanprovidethisporttoclientsasKubernetesservice.

kind:ServiceapiVersion:v1metadata:name:hello-jettynamespace:defaultselfLink:/api/v1/namespaces/default/services/hello-jettyuid:citrus:randomUUID()labels:service:hello-jettyspec:ports:-protocol:TCP

CitrusReferenceGuide

372Kubernetes

Page 373: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

port:8080targetPort:8080nodePort:31citrus:randomNumber(3)selector:server:hello-jettytype:NodePortsessionAffinity:None

Theserviceresourcemapstheport8080andselectsallpodswithlabelserver=hello-jetty.Thismakesthejettycontaineravailabletoclients.TheservicetypeisNodePortwhichmeansthatclientsoutsideofKubernetesarealsoabletoaccesstheservicebyusingthedynamicportnodePort=31xxx.WecanuseCitrusfunctionssuchasrandomNumberintheYAMLfiles.

InthetestcasewecanusetheseYAMLfilestocreatetheresourcesinKubernetes:

XMLDSL

<k8s:create-podnamespace="default"><k8s:templatefile="classpath:templates/hello-jetty-pod.yml"/></k8s:create-pod>

<k8s:create-servicenamespace="default"><k8s:templatefile="classpath:templates/hello-jetty-service.yml"/></k8s:create-service>

JavaDSL

@CitrusTestpublicvoidcreatePodsTest()kubernetes().pods().create(newClassPathResource("templates/hello-jetty-pod.yml")).namespace("default");

kubernetes().services().create(newClassPathResource("templates/hello-jetty-service.yml")).namespace("default");

Creatingnewresourcesmaytakesometimetofinish.Kuberneteswillhavetopullimages,buildcontainersandstartupeverything.Thecreateactionisnotwaitingsynchronouslyforallthattohavehappened.Thereforewemightaddalist-podsactionthatwaitsforthenewresourcestoappear.

CitrusReferenceGuide

373Kubernetes

Page 374: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<repeat-onerror-until-truecondition="@assertThat('greaterThan(9)')@"auto-sleep="1000"><k8s:list-podslabel="server=hello-jetty"><k8s:validate><k8s:elementpath="$.result.items.size()"value="1"/><k8s:elementpath="$..status.phase"value="Running"/></k8s:validate></k8s:list-pods></repeat-onerror-until-true>

Withthisrepeatonerroractionwewaitforthenewserver=hello-jettylabeledpodtobeinstateRunning.

Deleteresources

WiththatcommandweareabletodeletearesourceinKubernetes.Uptonowdeletionofpodsandservicesissupported.Wehavetogiveanameoftheresourcethatwewanttodelete.

XMLDSL

<k8s:delete-podname="citrus_pod"><k8s:validate><k8s:elementpath="$.result.success"value="true"/></k8s:validate></k8s:delete-pod>

JavaDSL

@CitrusTestpublicvoiddeletePodsTest()kubernetes().pods().delete("citrus_pod").validate((result,context)->Assert.assertTrue(result.getResult().getSuccess()));

Watchresources

NoteThewatchoperationisstillinexperimentalstateandmayfacesevereadjustmentsandimprovementsinnearfuture.

CitrusReferenceGuide

374Kubernetes

Page 375: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

WhenusingawatchcommandweaddasubscriptiontochangeeventsonaKubernetesresources.Sowecanwatchresourcessuchaspods,servicesforfuturechanges.Eachchangeonthatresourcetriggersanewwatcheventresultthatwecanexpectandvalidate.

XMLDSL

<k8s:watch-podslabel="provider=citrus"><k8s:validate><k8s:elementpath="$.action"value="DELETED"/></k8s:validate></k8s:watch-pods>

JavaDSL

@CitrusTestpublicvoidlistPodsTest()kubernetes().pods().watch().label("provider=citrus").validate((watchEvent,context)->Assert.assertFalse(watchEvent.hasError());Assert.assertEquals(((WatchEventResult)watchEvent).getAction(),Watcher.Action.DELETED););

NoteThewatchcommandmaybetriggeredseveraltimesformultiplechangesontherespectiveKubernetesresource.Thewatchactionwillalwayshandleonesingleeventresult.Thefirsteventtriggerisforwardedtotheactionvalidation.Allfurtherwatcheventsonthatsameresourceareignored.Thismeansthatyoumayneedmultiplewatchactionsinyourtestcaseincaseyouexpectmultiplewatcheventstobetriggered.

Kubernetesmessaging

WehaveseenhowtoaccesstheKubernetesremoteRESTAPIbyusingspecialCitrustestactionsinouttest.Asanalternativetothatwecanalsousemoregenericsend/receiveactionsinCitrusforaccessingtheKubernetesAPI.Wedemonstratethiswithasimpleexample:

XMLDSL

CitrusReferenceGuide

375Kubernetes

Page 376: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<testcasename="KubernetesSendReceiveIT"><actions><sendendpoint="k8sClient"><message><data>"command":"info"</data></message></send>

<receiveendpoint="k8sClient"><messagetype="json"><data>"command":"info","result":"clientVersion":"1.4.27","apiVersion":"v1","kind":"Info","masterUrl":"$masterUrl","namespace":"test"</data></message></receive>

<echo><message>Listallpods</message></echo>

<sendendpoint="k8sClient"><message><data>"command":"list-pods"</data></message></send>

<receiveendpoint="k8sClient"><messagetype="json"><data>"command":"list-pods","result":"apiVersion":"v1","kind":"PodList","metadata":"@ignore@","items":[]</data><validatepath="$.result.items.size()"value="0"/></message></receive>

CitrusReferenceGuide

376Kubernetes

Page 377: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</actions></testcase>

Asyoucanseewecanusethesend/receiveactionstocallKubernetesAPIcommandsandreceivetherespectiveresultsinJsonformat,too.ThisgivesusthewellknownJsonvalidationmechanisminCitrusinordertovalidatetheresultsfromKubernetes.ThiswayyoucanloadKubernetesresourcesverifyingitsstateandproperties.OfcourseJsonPathexpressionsalsocomeinhereinordertovalidateJsonelementsexplicitly.

CitrusReferenceGuide

377Kubernetes

Page 378: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

SSHsupportInthespiritofotherCitrusmockservices,thereissupportforsimulatinganexternalSSHserveraswellasforconnectingtoSSHserversasaclientduringthetestexecution.CitrustranslatesSSHrequestsandresponsestosimpleXMLdocumentsforbettervalidationwiththecommonCitrusmechanisms.

ThismeansthattheCitrustestcasedoesnotdealwithpureSSHprotocolcommands.InsteadofthisweusethepowerfulXMLvalidationcapabilitiesinCitruswhendealingwiththesimpleXMLdocumentsthatrepresenttheSSHrequest/responsedata.

Letusclarifythiswithalittleexample.OncetherealSSHserverdaemonisfiredupwithinCitrusweacceptaSSHEXECrequestforinstance.TherequestistranslatedintoaXMLmessageofthefollowingformat:

<ssh-requestxmlns="http://www.citrusframework.org/schema/ssh/message"><command>cat-|sed-e's/Hello/HelloSSH/'</command><stdin>HelloWorld</stdin></ssh-request>

ThismessagecanbevalidatedwiththeusualCitrusmechanisminareceivetestaction.Ifyoudonotknowhowtodothis,pleasereadoneofthesectionsaboutXMLmessagevalidationinthisreferenceguidefirst.NowafterhavingreceivedthisrequestmessagetherespectiveSSHresponseshouldbeprovidedasappropriateanswer.ThisisdonewithamessagesendingactiononareplyhandlerasitisknownfromsynchronoushttpmessagecommunicationinCitrusforinstance.TheSSHXMLrepresentationofaresponsemessagelookslikethis:

<ssh-responsexmlns="http://www.citrusframework.org/schema/ssh/message"><stdout>HelloSSHWorld</stdout><stderr></stderr><exit>0</exit></ssh-response>

BesidessimulatingafullfeaturedSSHserver,CitrusalsoprovidesSSHclientfunctionality.Thisclientusesthesamerequestmessagepattern,whichistranslatedintoarealSSHcalltoanSSHserver.TheSSHresponsereceivedisalsotranslatedintoaXMLmessageasshownabovesowecanvalidateitwithknownvalidationmechanismsinCitrus.

CitrusReferenceGuide

378Ssh

Page 379: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

SimilartotheotherCitrusmodules(http,soap),aCitrusSSHserverandclientisconfiguredinCitrusSpringapplicationcontext.ThereisadedicatedsshnamespaceavailableforallsshCitruscomponents.Thenamespacedeclarationgoesintothecontexttop-levelelementasusual:

<beans[...]xmlns:citrus-ssh="http://www.citrusframework.org/schema/ssh/config"[...]xsi:schemaLocation="[...]http://www.citrusframework.org/schema/ssh/confighttp://www.citrusframework.org/schema/ssh/config/citrus-ssh-config.xsd[...]">[...]</beans>

Both,SSHserverandclientalongwiththeirconfigurationoptionsaredescribedinthefollowingtwosections.

SSHClient

ACitrusSSHclientisusefulfortestingagainstarealSSHserver.SoCitrusisabletoinvokeSSHcommandsontheexternalserverandvalidatetheSSHresponseaccordingly.ThetestcasedoesnotdealwiththepureSSHprotocolwithinthiscommunication.TheCitrusSSHclientcomponentexpectsacustomizedXMLrepresentationandautomaticallytranslatestheserequestmessagesintoarealSSHcalltoaspecifichost.OncethesynchronousSSHresponsewasreceivedtheresultgetstranslatedbacktotheXMLresponsemessagerepresentation.OnthistranslatedresponsewecaneasilyapplythevalidationstepsbytheusualCitrusmeans.

TheSSHclientcomponentsreceiveitsconfigurationintheSpringapplicationcontextasusual.WecanusethespecialSSHmodulenamespaceforeasyconfiguration:

<citrus-ssh:clientid="sshClient"port="9072"user="roland"private-key-path="classpath:com/consol/citrus/ssh/test_user.priv"strict-host-checking="false"host="localhost"/>

TheSSHclientreceivesseveralattributes,theseare:

CitrusReferenceGuide

379Ssh

Page 380: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

id:Ididentifyingthebeanandusedasreferencefromwithtestdescriptions.(e.g.id="sshClient")host:HosttoconnecttoforsendinganSSHExecrequest.Defaultis'localhost'(e.g.host="localhost")portPorttouse.Defaultis2222(e.g.port="9072")private-key-path:Pathtoaprivatekey,whichcanbeeitheraplainfilepathoranclassresourceifprefixedwith'classpath'(e.g.private-key-path="classpath:test_user.priv")private-key-password:Optionalpasswordfortheprivatekey(e.g.password="s!cr!t")user:UserusedforconnectingtotheSSHserver(e.g.user="roland")password:Passwordusedforpasswordbasedauthentication.Mightbecombinedwith"private-key-path"inwhichcasebothauthenticationmechanismaretried(e.g.password="ps!st)strict-host-checking:Whetherthehostkeyshouldbeverifiedbylookingitupina'known_hosts'file.Defaultisfalse(e.g.strict-host-checking="true")known-hosts-path:Pathtoaknownhostsfile.Ifprefixedwith'classpath:'thisfileislookedupasaresourceintheclasspath(e.g.known-hosts-path="/etc/ssh/known_hosts")command-timeout:TimeoutinmillisecondsforhowlongtowaitfortheSSHcommandtocomplete.Defaultis5minutes(e.g.command-timeout="300000")connection-timeout:Timeoutinmillisecondsforhowlongtoforaconnectiuontoconnect.Defaultis1minute(e.g.connection-timeout="60000")actor:Actorusedforswitchinggroupsofactions(e.g.actor="ssh-mock")

OncedefinesasclientcomponentintheSpringapplicationcontexttestcasescanreferencetheclientineverysendtestaction.

<sendendpoint="sshClient"><message><payload><ssh-requestxmlns="http://www.citrusframework.org/schema/ssh/message"><command>shutdown</command><stdin>input</stdin></ssh-request></payload></message></send>

<receiveendpoint="sshClient"><message><payload>

CitrusReferenceGuide

380Ssh

Page 381: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<ssh-responsexmlns="http://www.citrusframework.org/schema/ssh/message"><stdout>HelloCitrus</stdout><stderr/><exit>0</exit></ssh-response></payload></message></receive>

Asyoucanseeweuseusualsendandreceivetestactions.TheXMLSSHrepresentationhelpsustospecifytherequestandresponsedataforvalidation.ThiswayyoucancallSSHcommandsagainstanexternalSSHserverandvalidatetheresponsedata.

SSHServer

NowthatwehaveusedCitrusontheclientsidewecanalsouseCitrusSSHservermoduleinordertoprovideafullstackedSSHserverdaemon.WecanacceptSSHclientconnectionsandprovideproperresponsemessagesasananswer.

GiventheaboveSSHmodulenamespacedeclaration,addinganewSSHserverisquitesimple:

<citrus-ssh:serverid="sshServer"allowed-key-path="classpath:com/consol/citrus/ssh/test_user_pub.pem"user="roland"port="9072"auto-start="true"endpoint-adapter="sshEndpointAdapter"/>

endpoint-adapteristhehandlerwhichreceivestheSSHrequestasmessages(intherequestformatdescribedabove).Endpointadapterimplementationsarefullydescribedinhttp-serverAlladaptersdescribedtherearesupportedinSSHservermodule,too.

The<citrus-ssh:server>supportsthefollowingattributes:

SSHServerAttributes:

id:NameoftheSSHserverwhichidentifiesituniquewithintheCitrusSpringcontext(e.g.id="sshServer")host-key-path:PathtoPEMencodedkeypair(publicandprivatekey)whichisusedashostkey.Bydefault,astandard,pre-generate,fixedkeypairisused.Thepathcanbespecifiedeitherasanfilepath,or,ifprefixedwithclasspath:islooked

CitrusReferenceGuide

381Ssh

Page 382: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

upfromwithintheclasspath.Thepaththeisrelativefromtothetop-levelpackage,sonoleadingslashshouldbeused(e.g.hist-key-path="/etc/citrus_ssh_server.pem)user:Userwhichisallowedtoconnect(e.g.user="roland")allowed-key-path:PathtoaSSHpublickeystoredinPEMformat.Thesearethekeys,whichareallowedtoconnecttotheSSHserverwhenpublickeyauthenticationisused.Itsevesthesamepurposeasauthorized_keysforstandardSSHinstallations.Thepathcanbespecifiedeitherasanfilepath,or,ifprefixedwithclasspath:islookedupfromwithintheclasspath.Thepaththeisrelativefromtothetop-levelpackage,sonoleadingslashshouldbeused(e.g.allowed-key-path="classpath:test_user_pub.pem)password:Passwordwhichshouldbeusedwhenpasswordauthenticationisused.Bothpublickeyauthenticationandpasswordbasedauthenticationcanbeusedtogetherinwhichcasebothmethodsaretriedinturn(e.g.password="s!cr!t")host:Hostaddress(e.g.localhost)port:Portonwhichtolisten.TheSSHserverwillbindonlocalhosttothisport(e.g.port="9072")auto-start:WhethertostartthisSSHserverautomatically.Defaultistrue.Ifsettofalse,atestactionisresponsibleforstarting/stoppingtheserver(e.g.auto-start="true")endpoint-adapter:BeanreferencetoaendpointadapterwhichprocessestheincomingSSHrequest.Themessageformatfortherequestandresponsearedescribedabove(e.g.endpoint-adapter="sshEndpointAdapter")

OncetheSSHservercomponentisaddedtotheSpringapplicationcontextwithaproperendpointadapterliketheMessageChannelforwardingadapterwecanreceiveincomingrequestsinatestcaseandprovidearesponemessagefortheclient.

<receiveendpoint="sshServer"><message><payload><ssh-requestxmlns="http://www.citrusframework.org/schema/ssh/message"><command>shutdown</command><stdin>input</stdin></ssh-request></payload></message></receive>

<sendendpoint="sshServer"><message><payload><ssh-responsexmlns="http://www.citrusframework.org/schema/ssh/message"><stdout>HelloCitrus</stdout>

CitrusReferenceGuide

382Ssh

Page 383: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<exit>0</exit></ssh-response></payload></message></send>

CitrusReferenceGuide

383Ssh

Page 384: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

RMIsupportRMIstandsforRemoteMethodInvocationandisastandardwayofcallingJavamethodinterfaceswherecallerandcallee(clientandserver)arenotlocatedwithinthesameJVM.Sotheobjectpassedtothemethodasargumentaswellasthemethodreturnvaluearetransmittedoverthewire.

AsaclientCitrusisabletoconnecttosomeRMIregistrythatexposessomeremoteinterfaces.AsaserverCitrusimplementssuchaRMIregistryandhandlesincomingmethodcallswithprovidingtherespectivereturnvalue.

NoteTheRMIcomponentsinCitrusarekeptinaseparateMavenmodule.SoyoushouldcheckthatthemoduleisavailableasMavendependencyinyourproject

<dependency><groupId>com.consol.citrus</groupId><artifactId>citrus-rmi</artifactId><version>2.7.1</version></dependency>

AsusualCitrusprovidesacustomizedrmiconfigurationschemathatisusedinSpringconfigurationfiles.Simplyincludethecitrus-rminamespaceintheconfigurationXMLfilesasfollows.

<beansxmlns="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-rmi="http://www.citrusframework.org/schema/rmi/config"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/confighttp://www.citrusframework.org/schema/config/citrus-config.xsdhttp://www.citrusframework.org/schema/rmi/confighttp://www.citrusframework.org/schema/rmi/config/citrus-rmi-config.xsd">

[...]

</beans>

NowyouarereadytousethecustomizedHttpconfigurationelementswiththecitrus-rminamespaceprefix.

CitrusReferenceGuide

384Rmi

Page 385: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ReadthenextsectioninordertofindoutmoreabouttheRMImessagesupportinCitrus.

RMIclient

Ontheclientsidewewanttocalleremoteinterface.Weneedtospecifythemethodtocallaswellasallmethodarguments.Therespectivemethodreturnvalueisreceivablewithinthetestcaseforvalidation.CitrusprovidesaclientcomponentforRMIthatsendsoutserviceinvocationcalls.

<citrus-rmi:clientid="rmiClient1"host="localhost"port="1099"binding="newsService"/>

<citrus-rmi:clientid="rmiClient2"server-url="rmi://localhost:1099/newsService"/>

TheclientcomponentintheSpringapplicationcontextreceiveshostandportconfigurationofavalidRMIserviceregistry.Eitherbyspecifyingaproperserverurlorbygivinghost,portandbindingproperties.Theservicebindingisthenameoftheservicethatwewouldliketoaddressintheregistry.Nowwearereadytousethisclientreferencedbyitsidornameinatestcaseforamessagesendingaction.

XMLDSL

<sendendpoint="rmiClient"><message><payload><service-invocationxmlns="http://www.citrusframework.org/schema/rmi/message"><remote>com.consol.citrus.rmi.remote.NewsService</remote><method>getNews</method></service-invocation></payload></message></send>

JavaDSL

@CitrusTestpublicvoidrmiClientTest()send(rmiClient).message(RmiMessage.invocation(NewsService.class,"getNews"));

CitrusReferenceGuide

385Rmi

Page 386: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

WeareusingtheusualCitrussendmessageactionreferencingthermiClientasendpoint.ThemessagepayloadisaspecialCitrusmessagethatdefinestheserviceinvocation.Wedefinetheremoteinterfaceaswellasthemethodtocall.CitrusRMIclientcomponentwillbeabletointerpretthismessagecontentandcalltheservicemethod.

Themethodreturnvalueisreceivableforvalidationusingtheverysameclientendpoint.

XMLDSL

<receiveendpoint="rmiClient"><message><payload><service-resultxmlns="http://www.citrusframework.org/schema/rmi/message"><objecttype="java.lang.String"value="ThisisnewsfromRMI!"/></service-result></payload></message></receive>

JavaDSL

@CitrusTestpublicvoidrmiClientTest()receive(rmiClient).message(RmiMessage.result("ThisisnewsfromRMI!"));

Inthesampleabovewereceivetheserviceresultandexpectajava.lang.Stringobjectreturnvalue.Thereturnvaluecontentisalsovalidatedwithintheserviceresultpayload.

Ofcoursewecanalsodealwithmethodarguments.

XMLDSL

<sendendpoint="rmiClient"><message><payload><service-invocationxmlns="http://www.citrusframework.org/schema/rmi/message"><remote>com.consol.citrus.rmi.remote.NewsService</remote><method>setNews</method><args><argvalue="Thisisbreakingnews!"/></args>

CitrusReferenceGuide

386Rmi

Page 387: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</service-invocation></payload></message></send>

@CitrusTestpublicvoidrmiServerTest()send(rmiClient).message(RmiMessage.invocation(NewsService.class,"setNews").argument("Thisisbreakingnews!"));

Thiscompletesthebasicremoteservicecall.Citrusinvokestheremoteinterfacemethodandvalidatesthemethodreturnvalue.Asatesteryoumightalsofaceerrorsandexceptionswhencallingtheremoteinterfacemethod.Youcancatchandasserttheseremoteexceptionsverifyingyourerrorscenario.

XMLDSL

<assertexception="java.rmi.RemoteException"><when><sendendpoint="rmiClient"><message><payload><service-invocationxmlns="http://www.citrusframework.org/schema/rmi/message"[...]</service-invocation></payload></message></send></when><assert/>

WeasserttheRemoteExceptiontobethrownwhilecallingtheremoteservicemethod.Thisishowyoucanhandlesomesortoferrorsituationwhilecallingremoteservices.InthenextsectionwewillhandleRMIcommunicationwhereCitrusprovidestheremoteinterfaces.

RMIserver

CitrusReferenceGuide

387Rmi

Page 388: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

OntheserversideCitrusneedstoprovideremoteinterfaceswithmethodscallableforclients.ThismeansthatCitrusneedstosupportallyourremoteinterfaceswithmethodargumentsandreturnvalues.TheCitrusRMIserverisabletobindyourremoteinterfacestoaserviceregistry.AllincomingRMIclientmethodcallsareautomaticallyacceptedandthemethodargumentsareconvertedintoaCitrusXMLserviceinvocationrepresentation.TheRMImethodcallisthenpassedtotherunningtestforvalidation.

LetushavealookattheCitrusRMIservercomponentandhowyoucanaddittotheSpringapplicationcontext.

<citrus-rmi:serverid="rmiServer"host="localhost"port="1099"interface="com.consol.citrus.rmi.remote.NewsService"binding="newService"create-registry="true"auto-start="true"/>

TheRMIservercomponentusespropertiessuchashostandporttodefinetheserviceregistry.BydefaultCitruswillconnecttothisserviceregistryandbinditsremoteinterfacestoit.Withtheattributecreate-registryCitruscanalsocreatetheregistryforyou.

YouhavetogiveCitrusthefullyqualifiedremoteinterfacenamesoCitruscanbindittotheserviceregistryandhandleincomingmethodcallsproperly.Inyourtestcaseyoucanthenreceivetheincomingmethodcallsontheserverinordertoperformvalidationsteps.

XMLDSL

<receiveendpoint="rmiServer"><message><payload><service-invocationxmlns="http://www.citrusframework.org/schema/rmi/message"><remote>com.consol.citrus.rmi.remote.NewsService</remote><method>getNews</method></service-invocation></payload><header><elementname="citrus_rmi_interface"value="com.consol.citrus.rmi.remote.NewsService"<elementname="citrus_rmi_method"value="getNews"/></header></message></receive>

CitrusReferenceGuide

388Rmi

Page 389: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

JavaDSL

@CitrusTestpublicvoidrmiServerTest()receive(rmiServer).message(RmiMessage.invocation(NewsService.class,"getNews"));

AsyoucanseeCitrusconvertstheincomingserviceinvocationtoaspecialXMLrepresentationwhichispassedasmessagepayloadtothetest.AsthisisplainXMLyoucanverifytheRMImessagecontentasusualusingCitrusvariables,functionsandvalidationmatchers.

Sincewehavereceivedthemethodcallweneedtoprovidesomereturnvaluefortheclient.AsusualwecanspecifythemethodreturnvaluewithsomeXMLrepresentation.

XMLDSL

<sendendpoint="rmiServer"><message><payload><service-resultxmlns="http://www.citrusframework.org/schema/rmi/message"><objecttype="java.lang.String"value="ThisisnewsfromRMI!"/></service-result></payload></message></send>

JavaDSL

@CitrusTestpublicvoidrmiServerTest()send(rmiServer).message(RmiMessage.result("ThisisnewsfromRMI!"));

Theserviceresultisdefinedasobjectwithatypeandvalue.TheCitrusRMIremoteinterfacemethodwillreturnthisvaluetothecallingclient.Thiswouldcompletethesuccessfulremoteserviceinvocation.Atthispointwealsohavetothinkofchoosingtoraisesomeremoteexceptionasserviceoutcome.

XMLDSL

CitrusReferenceGuide

389Rmi

Page 390: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<sendendpoint="rmiServer"><message><payload><service-resultxmlns="http://www.citrusframework.org/schema/rmi/message"><exception>Somethingwentwrong<exception/></service-result></payload></message></send>

JavaDSL

@CitrusTestpublicvoidrmiServerTest()send(rmiServer).message(RmiMessage.exception("Somethingwentwrong"));

IntheexampleaboveCitruswillnotreturnsomeobjectasserviceresultbutraiseajava.rmi.RemoteExceptionwithrespectiveerrormessageasspecifiedinthetestcase.Thecallingclientwillreceivetheexceptionaccordingly.

CitrusReferenceGuide

390Rmi

Page 391: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

JMXsupportJMXisastandardJavaAPIformakingbeansaccessibletoothersintermsofmanagementandremoteconfiguration.JMXistheshorttermforJavaManagementExtensionsandisoftenusedinJEEapplicationserverstomanagebeanattributesandoperationsfromoutside(e.g.anotherJVM).AmanagedbeanserverhostsmultiplemanagedbeansforJMXaccess.RemoteconnectionstoJMXcanberealizedwithRMI(Remotemethodinvocation)capabilities.

CitrusisabletoconnecttoJMXmanagedbeansasclientandserver.AsaclientCitruscaninvokemanagedbeanoperationsandreadwritemanagedbeanattributes.AsaserverCitrusisabletoexposemanagedbeansasmbeanserver.ClientscanaccessthoseCitrusmanagedbeansandgetproperresponseobjectsasresult.DoingsoyoucanusetheJVMplatformmanagedbeanserverorsomeRMIregistryforprovidingremoteaccess.

NoteTheJMXcomponentsinCitrusarekeptinaseparateMavenmodule.SoyoushouldcheckthatthemoduleisavailableasMavendependencyinyourproject

<dependency><groupId>com.consol.citrus</groupId><artifactId>citrus-jmx</artifactId><version>2.7.1</version></dependency>

AsusualCitrusprovidesacustomizedjmxconfigurationschemathatisusedinSpringconfigurationfiles.Simplyincludethecitrus-jmxnamespaceintheconfigurationXMLfilesasfollows.

<beansxmlns="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-jmx="http://www.citrusframework.org/schema/jmx/config"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/confighttp://www.citrusframework.org/schema/config/citrus-config.xsdhttp://www.citrusframework.org/schema/jmx/confighttp://www.citrusframework.org/schema/jmx/config/citrus-jmx-config.xsd">

[...]

CitrusReferenceGuide

391Jmx

Page 392: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</beans>

NowyouarereadytousethecustomizedHttpconfigurationelementswiththecitrus-jmxnamespaceprefix.

NextsectionsdescribetheJMXmessagesupportinCitrusinmoredetail.

JMXclient

Ontheclientsidewewanttocallsomemanagedbeanbyeitheraccessingmanagedattributeswithread/writeorbyinvokingamanagedbeanoperation.ForpropermbeanserverconnectivityweshouldspecifyaclientcomponentforJMXthatsendsoutmbeaninvocationcalls.

<citrus-jmx:clientid="jmxClient"server-url="platform"/>

Theclientcomponentspecifiesthetargetmanagedbeanserverthatwewanttoconnectto.InthisexampleweareusingtheJVMplatformmbeanserver.ThismeansweareabletoaccessallJVMmanagedbeanssuchasMemory,ThreadingandLogging.Inadditiontothatwecanaccessallcustommanagedbeansthatwereexposedtotheplatformmbeanserver.

InmostcasesyoumaywanttoaccessmanagedbeansonadifferentJVMorapplicationserver.Soweneedsomeremoteconnectiontotheforeignmbeanserver.

<citrus-jmx:clientid="jmxClient"server-url="service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi"username="user"password="s!cr!t"auto-reconnect="true"delay-on-reconnect="5000"/>

InthisexampleaboveweconnecttoaremotembeanserverviaRMIusingthedefaultRMIregistrylocalhost:1099andtheservicenamejmxrmi.Citrusisabletohandledifferentremotetransportprotocols.Justdefinethoseintheserver-url.

Nowthatwehavesetuptheclientcomponentwecanuseitinatestcasetoaccessamanagedbean.

XMLDSL

CitrusReferenceGuide

392Jmx

Page 393: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<sendendpoint="jmxClient"><message><payload><mbean-invocationxmlns="http://www.citrusframework.org/schema/jmx/message"><mbean>java.lang:type=Memory</mbean><attributename="Verbose"/></mbean-invocation></payload></message></send>

JavaDSL

@CitrusTestpublicvoidjmxClientTest()send(jmxClient).message(JmxMessage.invocation("java.lang:type=Memory").attribute("Verbose"));

Asyoucanseewejustusedanormalsendactionreferencingthejmxclientcomponentthatwehavejustadded.ThemessagepayloadisaXMLrepresentationofthemanagedbeanaccess.ThisisaspecialCitrusXMLrepresentation.CitruswillconvertthisXMLpayloadtotheactuelmanagedbeanaccess.Intheexampleabovewetrytoaccessamanagedbeanwithobjectnamejava.lang:type=Memory.TheobjectnameisdefinedinJMXspecificationandconsistsofakeyjava.lang:typeandavalueMemory.Soweidentifythemanagedbeanontheserverbyitstype.

NowthatwehaveaccesstothemanagedbeanwecanreaditsmanagedattributessuchasVerbose.ThisisabooleantypeattributesothembeaninvocationresultwillbearespectiveBooleanobject.Wecanvalidatethemanagedbeanattributeaccessinareceiveaction.

XMLDSL

<receiveendpoint="jmxClient"><message><payload><mbean-resultxmlns="http://www.citrusframework.org/schema/jmx/message"><objecttype="java.lang.Boolean"value="false"/></mbean-result></payload></message></receive>

CitrusReferenceGuide

393Jmx

Page 394: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

JavaDSL

@CitrusTestpublicvoidjmxClientTest()receive(jmxClient).message(JmxMessage.result(false));

Inthesampleabovewereceivethembeanresultandexpectajava.lang.Booleanobjectreturnvalue.Thereturnvaluecontentisalsovalidatedwithinthembeanresultpayload.

Somemanagedbeanattributesmightalsobesettableforus.Sowencandefinetheattributeaccessaswriteoperationbyspecifyingavalueinthesendactionpayload.

XMLDSL

<sendendpoint="jmxClient"><message><payload><mbean-invocationxmlns="http://www.citrusframework.org/schema/jmx/message"><mbean>java.lang:type=Memory</mbean><attributename="Verbose"value="true"type="java.lang.Boolean"/></mbean-invocation></payload></message></send>

JavaDSL

@CitrusTestpublicvoidjmxClientTest()send(jmxClient).message(JmxMessage.invocation("java.lang:type=Memory").attribute("Verbose",true));

NowwehavewriteaccesstothemanagedattributeVerbose.Wedospecifythevalueanditstypejava.lang.Boolean.Thisishowwecansetattributevaluesonmanagedbeans.

Lastnotleastweareabletoaccessmanagedbeanoperations.

XMLDSL

CitrusReferenceGuide

394Jmx

Page 395: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<sendendpoint="jmxClient"><message><payload><mbean-invocationxmlns="http://www.citrusframework.org/schema/jmx/message"><mbean>com.consol.citrus.jmx.mbean:type=HelloBean</mbean><operationname="sayHello">>parameter>>paramtype="java.lang.String"value="HelloJMX!"/>>/parameter>>/operation></mbean-invocation></payload></message></send>

JavaDSL

@CitrusTestpublicvoidjmxClientTest()send(jmxClient).message(JmxMessage.invocation("com.consol.citrus.jmx.mbean:type=HelloBean").operation("sayHello").parameter("HelloJMX!"));

IntheexampleaboveweaccessacustommanagedbeanandinvokeitsoperationsayHello.Wearealsousingoperationparametersfortheinvocation.Thisshouldcallthemanagedbeanoperationandreturnitsresultifanyasusual.

ThiscompletesthebasicJMXmanagedbeanaccessasclient.NowwealsowanttodiscusstheserversidewereCitrusisabletoprovidemanagedbeansforothers

JMXserver

Theserversideisalwaysalittlebitmoretrickybecauseweneedtosimulatecustommanagedbeanaccessasaserver.FirstofallCitrusprovidesaservercomponentthatspecifiestheconnectionpropertiesforclientssuchastransportprotocols,portsandmbeanobjectnames.LetscreateanewserverthatacceptsincomingrequestsviaRMIonaremoteregistrylocalhost:1099.

<citrus-jmx:serverid="jmxServer"server-url="service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi"<citrus-jmx:mbeans><citrus-jmx:mbeantype="com.consol.citrus.jmx.mbean.HelloBean"/><citrus-jmx:mbeantype="com.consol.citrus.jmx.mbean.NewsBean"objectDomain="com.consol.citrus.news"objectName="name=News"/>

CitrusReferenceGuide

395Jmx

Page 396: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</citrus-jmx:mbeans></citrus-jmx:server>

Asusualwedefineaserver-urlthatcontrolstheJMXconnectoraccesstothembeanserver.InthisexampleaboveweopenaJMXRMIconnectorforclientsusingtheregistrylocalhost:1099andtheservicenamejmxrmiBydefaultCitruswillnotattempttocreatethisregistryautomaticallysotheregistryhastobepresentbeforetheserverstartup.Withtheoptionalserverpropertycreate-registrysettotrueyoucanautocreatetheregistrywhentheserverstartsup.ThesepropertiesdoonlyapplywhenusingaremoteJMXconnectorserver.

Besidesusingthewholeserver-urlaspropertywecanalsoconstructtheconnectionbyhost,port,protocolandbindingproperties.

<citrus-jmx:serverid="jmxServer"host="localhost"port="1099"protocol="rmi"binding="jmxrmi"<citrus-jmx:mbeans><citrus-jmx:mbeantype="com.consol.citrus.jmx.mbean.HelloBean"/><citrus-jmx:mbeantype="com.consol.citrus.jmx.mbean.NewsBean"objectDomain="com.consol.citrus.news"objectName="name=News"/></citrus-jmx:mbeans></citrus-jmx:server>

Onlastthingtomentionisthatwecouldhavealsousedplatformasserver-urlinordertousetheJVMplatformmbeanserverinstead.

NowthatweclarifiedtheconnectivityweneedtotalkabouthowtodefinethemanagedbeansthatareavailableonourJMXmbeanserver.Thisisdoneasnestedmbeanconfigurationelements.HerethemanagedbeandefinitionsdescribethemanagedbeanwithitsobjectDomain,objectName,operationsandattributes.Themostconvenientwayofdefiningsuchmanagedbeandefinitionsistogiveabeantypewhichisthefullyqualifiedclassnameofthemanagedbean.CitruswillusethepackagenameandclassnameforproperobjectDomainandobjectNameconstruction.

Letshaveacloserlookattheirstmbeandefinitionintheexampleabove.Sothefirstmanagedbeanisdefinedbyitsclassnamecom.consol.citrus.jmx.mbean.HelloBeanandthereforeisaccessibleusingtheobjectNamecom.consol.citrus.jmx.mbean:type=HelloBean.InadditiontothatCitruswillreadthe

CitrusReferenceGuide

396Jmx

Page 397: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

classinformationsuchasavailablemethods,gettersandsettersforconstructingaproperMBeanInfo.InthesecondmanagedbeandefinitioninourexamplewehaveusedadditionalcustomobjectDomainandobjectNamevalues.SotheNewsBeanwillbeaccessiblewithcom.consol.citrus.news:name=Newsonthemanagedbeanserver.

Thisishowwecandefinethebindingsofmanagedbeansandwhatclientsneedtosearchforwhenfindingandaccessingthemanagedbeansontheserver.WhenclientstrytofindthemanagedbeanstheyhavetouseproperobjectNamesaccordingly.ObjectNamesthatarenotdefinedontheserverwillberejectedwithmanagedbeannotfounderror.

Rightnowwehavetousethequalifiedclassnameofthemanagedbeaninthedefinition.Whathappensifwedonothaveaccesstothatmbeanclassorifthereisnotmanagedbeaninterfaceavailableatall?Citrusprovidesagenericmanagedbeanthatisabletohandleanymanagedbeaninteraction.Thegenericbeanimplementationneedstoknowthemanagedoperationsandattributesthough.Soletsdefineanewgenericmanagedbeanonourserver:

<citrus-jmx:serverid="jmxServer"server-url="service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi"<citrus-jmx:mbeans><citrus-jmx:mbeanname="fooBean"objectDomain="foo.object.domain"objectName="type=FooBean"><citrus-jmx:operations><citrus-jmx:operationname="fooOperation"><citrus-jmx:parameter><citrus-jmx:paramtype="java.lang.String"/><citrus-jmx:paramtype="java.lang.Integer"/></citrus-jmx:parameter></citrus-jmx:operation><citrus-jmx:operationname="barOperation"/></citrus-jmx:operations><citrus-jmx:attributes><citrus-jmx:attributename="fooAttribute"type="java.lang.String"/><citrus-jmx:attributename="barAttribute"type="java.lang.Boolean"/></citrus-jmx:attributes></citrus-jmx:mbean></citrus-jmx:mbeans></citrus-jmx:server>

Thegenericbeandefinitionneedstodefinealloperationsandattributesthatareavailableforaccess.UptonowwearerestrictedtousingJavabasetypeswhendefiningoperationparameterandattributereturntypes.Thereisactuallynowaytodefinemore

CitrusReferenceGuide

397Jmx

Page 398: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

complexreturntypes.NeverthelessCitrusisnowabletoexposethemanagedbeanforclientaccesswithouthavingtoknowtheactualmanagedbeanimplementation.

Nowwecanusetheservercomponentinatestcasetoreceivesomeincomingmanagedbeanaccess.

XMLDSL

<receiveendpoint="jmxServer"><message><payload><mbean-invocationxmlns="http://www.citrusframework.org/schema/jmx/message"><mbean>com.consol.citrus.jmx.mbean:type=HelloBean</mbean><operationname="sayHello">>parameter>>paramtype="java.lang.String"value="HelloJMX!"/>>/parameter></operation></mbean-invocation></payload></message></receive>

JavaDSL

@CitrusTestpublicvoidjmxServerTest()receive(jmxServer).message(JmxMessage.invocation("com.consol.citrus.jmx.mbean:type=HelloBean").operation("sayHello").parameter("HelloJMX!"));

Inthisveryfirstexampleweexpectamanagedbeanaccesstothebeancom.consol.citrus.jmx.mbean:type=HelloBean.WefurtherexpecttheoperationsayHellotobecalledwithrespectiveparametervalues.Nowwehavetodefinetheoperationresultthatwillbereturnedtothecallingclientasoperationresult.

XMLDSL

<sendendpoint="jmxServer"><message><payload><mbean-resultxmlns="http://www.citrusframework.org/schema/jmx/message"><objecttype="java.lang.String"value="HellofromJMX!"/></mbean-result>

CitrusReferenceGuide

398Jmx

Page 399: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</payload></message></send>

JavaDSL

@CitrusTestpublicvoidjmxServerTest()send(jmxServer).message(JmxMessage.result("HellofromJMX!"));

TheoperationreturnsaStringHellofromJMX!.Thisishowwecanexpectoperationcallsonmanagedbeans.Nowwealreadyhaveseenthatmanagedbeansalsoexposeattributes.Thenextexampleishandlingincomingattributereadaccess.

XMLDSL

<receiveendpoint="jmxServer"><message><payload><mbean-invocationxmlns="http://www.citrusframework.org/schema/jmx/message"><mbean>com.consol.citrus.news:name=News</mbean>>attributename="newsCount"/></mbean-invocation></payload></message></receive>

<sendendpoint="jmxServer"><message><payload><mbean-resultxmlns="http://www.citrusframework.org/schema/jmx/message"><objecttype="java.lang.Integer"value="100"/></mbean-result></payload></message></send>

JavaDSL

@CitrusTestpublicvoidjmxServerTest()receive(jmxServer).message(JmxMessage.invocation("com.consol.citrus.news:name=News").attribute("newsCount");

CitrusReferenceGuide

399Jmx

Page 400: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

send(jmxServer).message(JmxMessage.result(100));

ThereceiveactionexpectsreadaccesstotheNewsBeanattributenewsCountandreturnsaresultobjectoftypejava.lang.Integer.Thiswaywecanexpectallattributeaccesstoourmanagedbeans.Writeoperationswillhaveaattributevaluespecified.

ThiscompletestheJMXservercapabilitieswithmanagedbeanaccessonoperationsandattributes.

CitrusReferenceGuide

400Jmx

Page 401: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

CucumberBDDsupportBehaviordrivendevelopment(BDD)isbecomingmoreandmorepopularthesedays.Theideaofdefininganddescribingthesoftwarebehaviorasbasisforalltestsinpriortotranslatingthosefeaturedescriptionsintoexecutabletestsisaveryinterestingapproachbecauseitincludesthetechnicalexpertsaswellasthedomainexperts.WithBDDthedomainexpertscaneasilyreadandverifythetestsandthetechnicalexpertsgetadetaileddescriptionofwhatshouldhappeninthetest.

ThetestscenariodescriptionsfollowtheGherkinsyntaxwitha"Given-When-Then"structuremostofthetime.TheGherkinlanguageisbusinessreadableandwellknowninBDD.

TherearelotsofframeworksintheJavacommunitythatsupportBDDconcepts.CitrushasdedicatedsupportfortheCucumberframeworkbecauseCucumberiswellsuitedforextensionsandplugins.SowiththeCitrusandCucumberintegrationyoucanwriteGherkinsyntaxscenarioandfeaturestoriesinordertoexecutetheCitrusintegrationtestcapabilities.Asusualwehavealookatafirstexample.FirstletsseetheCitruscucumberdependencyandXMLschemadefinitions.

NoteTheCucumbercomponentsinCitrusarekeptinaseparateMavenmodule.IfnotalreadydonesoyouhavetoincludethemoduleasMavendependencytoyourproject

<dependency><groupId>com.consol.citrus</groupId><artifactId>citrus-cucumber</artifactId><version>2.7.1</version></dependency>

CitrusprovidesaseparateconfigurationnamespaceandschemadefinitionforCucumberrelatedstepdefinitions.IncludethisnamespaceintoyourSpringconfigurationinordertousetheCitrusCucumberconfigurationelements.ThenamespaceURIandschemalocationareaddedtotheSpringconfigurationXMLfileasfollows.

<spring:beansxmlns:spring="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://www.citrusframework.org/schema/cucumber/testcase"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/cucumber/testcase

CitrusReferenceGuide

401Cucumber

Page 402: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

http://www.citrusframework.org/schema/cucumber/testcase/citrus-cucumber-testcase.xsd">

[...]

</spring:beans>

CucumberworkswithbothJUnitandTestNGasunittestingframework.YoucanchoosewhichframeworktousewithCucumber.SofollowingfromthatweneedaMavendependencyfortheunittestingframeworksupport:

<dependency><groupId>info.cukes</groupId><artifactId>cucumber-junit</artifactId><version>$cucumber.version</version></dependency>

InordertoenableCitrusCucumbersupportweneedtospecifyaspecialobjectfactoryintheenvironment.Themostcomfortablewaytospecifyacustomobjectfactoryistoaddthispropertytothecucumber.propertiesinclasspath.

cucumber.api.java.ObjectFactory=cucumber.runtime.java.CitrusObjectFactory

Thisspecialobjectfactorytakescareoncreatingallstepdefinitioninstances.Theobjectfactoryisabletoinject@CitrusResourceannotatedfieldsinstepclasses.Wewillseethislateronintheexamples.TheusageofthisspecialobjectfactoryismandatoryinordertocombineCitrusandCucumbercapabilities.

TheCitrusObjectFactorywillautomaticallyinitializetheCitrusworldforus.Thisincludesthedefaultcitrus-context.xmlCitrusSpringconfigurationthatisautomaticallyloadedwithintheobjectfactory.SoyoucandefineanduseCitruscomponentsasusualwithinyourtest.

AfterthesepreparationstepsyouareabletocombineCitrusandCucumberinyourproject.

Cucumberintegration

CucumberisabletoruntestswithJUnit.ThebasictestcaseisanemptytestwhichusestherespectiveJUnitrunnerimplementationfromcucumber.

CitrusReferenceGuide

402Cucumber

Page 403: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

@RunWith(Cucumber.class)@CucumberOptions(plugin="com.consol.citrus.cucumber.CitrusReporter")publicclassMyFeatureIT

ThetestcaseaboveusestheCucumberJUnittestrunner.InadditiontothatwegivesomeoptionstotheCucumberexecution.WedefineaspecialCitrusreporterimplementation.ThisclassisresponsibleforprintingtheCitrustestsummary.ThisreporterextendsthedefaultCucumberreporterimplementationsothedefaultCucumberreportsummariesarealsoprintedtotheconsole.

ThatcompletestheJUnitclassconfiguration.NowweareabletoaddfeaturestoriesandstepdefinitionstothepackageofourtestMyFeatureIT.CucumberandCitruswillautomaticallypickupstepdefinitionsandgluecodeinthattestpackage.Soletswriteafeaturestoryecho.featurerightnexttotheMyFeatureITtestclass.

Feature:Echoservice

Scenario:SayhelloGivenMynameisCitrusWhenIsayhellototheserviceThentheserviceshouldreturn:"Hello,mynameisCitrus!"

Scenario:SaygoodbyeGivenMynameisCitrusWhenIsaygoodbyetotheserviceThentheserviceshouldreturn:"GoodbyefromCitrus!"

AsyoucanseethisstorydefinestwoscenarioswiththeGherkinGiven-When-Thensyntax.NowweneedtoaddstepdefinitionsthatgluethestorydescriptiontoCitrustestactions.LetsdothisinanewclassEchoSteps.

publicclassEchoSteps

@CitrusResourceprotectedTestDesignerdesigner;

@Given("^Mynameis(.*)$")publicvoidmy_name_is(Stringname)designer.variable("username",name);

@When("^Isayhello.*$")

CitrusReferenceGuide

403Cucumber

Page 404: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

publicvoidsay_hello()designer.send("echoEndpoint").messageType(MessageType.PLAINTEXT).payload("Hello,mynameis$username!");

@When("^Isaygoodbye.*$")publicvoidsay_goodbye()designer.send("echoEndpoint").messageType(MessageType.PLAINTEXT).payload("Goodbyefrom$username!");

@Then("^theserviceshouldreturn:\"([^\"]*)\"$")publicvoidverify_return(finalStringbody)designer.receive("echoEndpoint").messageType(MessageType.PLAINTEXT).payload("Youjustsaid:"+body);

IfwehaveacloserlookatthestepdefinitionclassweseethatitisanormalPOJOthatusesa@CitrusResourceannotatedTestDesigner.ThetestdesignerisautomaticallyinjectedbyCitrusCucumberextension.Thisisdonebecausewehaveincludedthecitrus-cucumberdependencytoourprojectbefore.Nowwecanwrite@Given,@Whenor@Thenannotatedmethodsthatmatchthescenariodescriptionsinourstory.Cucumberwillautomaticallyfindmatchingmethodsandexecutethem.ThemethodsaddtestactionstothetestdesignerasweareusedtoitinnormalJavaDSLtests.Attheendthetestdesignerisautomaticallyexecutedwiththetestlogic.

ImportantOfcourseyoucandothedependencyinjectionwith@CitrusResourceannotationsonTestRunnerinstances,too.WhichvariationshouldsomeoneuseTestDesignerorTestRunner?Infactthereisasignificantdifferencewhenlookingatthetwoapproaches.ThedesignerwillusetheGherkinmethodstobuildthewholeCitrustestcasefirstbeforeanyactionisexecuted.TherunnerwillexecuteeachtestactionthathasbeenbuiltwithaGherkinstepimmediately.ThismeansthatadesignerapproachwillalwayscompleteallBDDstepdefinitionsbeforetakingaction.ThisdirectlyaffectstheCucumberstepreports.AllstepsareusuallymarkedassuccessfulwhenusingadesignerapproachastheCitrustestisexecutedaftertheCucumberstepshavebeenexecuted.Therunnerapproachincontrastwillfailthestepwhenthecorrespondingtestactionfails.TheCucumbertestreportswilldefinitelylookdifferent

CitrusReferenceGuide

404Cucumber

Page 405: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

dependingonwhatapproachyouarechoosing.Allotherfunctionsstaythesameinbothapproaches.Ifyouneedtolearnmoreaboutdesignerandrunnerapproachespleasesee

IfweruntheCucumbertesttheCitrustestcaseautomaticallyperformsitsactions.ThatisafirstcombinationofCitrusandCucumberBDD.Thestorydescriptionsaretranslatedtotestactionsandweareabletorunintegrationtestswithbehaviordrivendevelopment.Great!InanextstepwewilluseXMLstepdefinitionsratherthancodingthestepsinJavaDSL.

CucumberXMLsteps

SofarwehavewrittengluecodeinJavainordertotranslateGherkinsyntaxdescriptionstotestactions.NowwewanttodothesamewithjustXMLconfiguration.TheJUnitCucumberclassshouldnotchange.WestillusetheCucumberrunnerimplementationwithsomeoptionsspecifictoCitrus:

@RunWith(Cucumber.class)@CucumberOptions(plugin="com.consol.citrus.cucumber.CitrusReporter")publicclassMyFeatureIT

Thescenariodescriptionisalsonotchanged:

Feature:Echoservice

Scenario:SayhelloGivenMynameisCitrusWhenIsayhellototheserviceThentheserviceshouldreturn:"Hello,mynameisCitrus!"

Scenario:SaygoodbyeGivenMynameisCitrusWhenIsaygoodbyetotheserviceThentheserviceshouldreturn:"GoodbyefromCitrus!"

Inthefeaturepackagemy.company.featuresweaddanewXMLfileEchoSteps.xmlthatholdsthenewXMLstepdefinitions:

<?xmlversion="1.0"encoding="UTF-8"?><spring:beansxmlns:citrus="http://www.citrusframework.org/schema/testcase"

CitrusReferenceGuide

405Cucumber

Page 406: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

xmlns:spring="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://www.citrusframework.org/schema/cucumber/testcase"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/cucumber/testcasehttp://www.citrusframework.org/schema/cucumber/testcase/citrus-cucumber-testcase.xsd"

<stepgiven="^Mynameis(.*)$"parameter-names="username"><citrus:create-variables><citrus:variablename="username"value="$username"/></citrus:create-variables></step>

<stepwhen="^Isayhello.*$"><citrus:sendendpoint="echoEndpoint"><citrus:messagetype="plaintext"><citrus:data>Hello,mynameis$username!</citrus:data></citrus:message></citrus:send></step>

<stepwhen="^Isaygoodbye.*$"><citrus:sendendpoint="echoEndpoint"><citrus:messagetype="plaintext"><citrus:data>Goodbyefrom$username!</citrus:data></citrus:message></citrus:send></step>

<stepthen="^theserviceshouldreturn:&quot;([^&quot;]*)&quot;$"parameter-names="body"><citrus:receiveendpoint="echoEndpoint"><citrus:messagetype="plaintext"><citrus:data>Youjustsaid:$body</citrus:data></citrus:message></citrus:receive></step>

</spring:beans>

TheabovestepsdefinitioniswritteninpureXML.CitruswillautomaticallyreadthestepdefinitionandaddthosetotheCucumberruntime.Followingfromthatthestepdefinitionsareexecutedwhenmatchingtothefeaturestory.TheXMLstepfilesfollowanamingconvention.Citruswilllookforallfileslocatedinthefeaturepackagewithnamepattern**/.Steps.xml**andloadthosedefinitionswhenCucumberstartsup.

CitrusReferenceGuide

406Cucumber

Page 407: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TheXMLstepsareabletoreceiveparametersfromtheGherkinregexpmatcher.Theparametersarepassedtothestepastestvariable.Theparameternamesgetdeclaredintheoptionalattributeparameter-names.Inthestepdefinitionactionsyoucanusetheparameternamesastestvariables.

NoteThetestvariablesarevisibleinallupcomingsteps,too.Thisisbecausethetestvariablesareglobalbydefault.Ifyouneedtosetlocalstateforastepdefinitionyoucanuseanotherattributeglobal-contextandsetittofalseinthestepdefinition.Thiswayalltestvariablesandparametersareonlyvisibleinthestepdefinition.Otherstepswillnotseethetestvariables.

NoteAnothernotablethingistheXMLescapingofreservedcharactersinthepatterndefinition.Youcanseethatinthelaststepwherethethenattributeisescapingquotationcharacters.

then="^theserviceshouldreturn:&quot;([^&quot;]*)&quot;$"

WehavetodothisbecauseotherwisethequotationcharacterswillinterferewiththeXMLsyntaxintheattribute.

ThiscompletesthedescriptionofhowtoaddXMLstepdefinitionstothecucumberBDDtests.Inanextsectionwewillusepredefinedstepsforsendingandreceivingmessages.

CucumberSpringsupport

CucumberprovidessupportforSpringdependencyinjectioninstepdefinitionclasses.TheCucumberSpringcapabilitiesareincludedinaseparatemodule.Sowefirstofallwehavetoaddthisdependencytoourproject:

<dependency><groupId>info.cukes</groupId><artifactId>cucumber-spring</artifactId><version>$cucumber.version</version></dependency>

TheCitrusCucumberextensionhastohandlethingsdifferentwhenCucumberSpringsupportisenabled.ThereforeweuseanotherobjectfactoryimplementationthatalsosupportCucumberSpringfeatures.Changetheobjectfactorypropertyincucumber.propertiestothefollowing:

CitrusReferenceGuide

407Cucumber

Page 408: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

cucumber.api.java.ObjectFactory=cucumber.runtime.java.spring.CitrusSpringObjectFactory

Nowwearereadytoadd@AutowiredSpringbeandependenyinjectiontostepdefinitionclasses:

@ContextConfiguration(classes=CitrusSpringConfig.class)publicclassEchoSteps@AutowiredprivateEndpointechoEndpoint;

@CitrusResourceprotectedTestDesignerdesigner;

@Given("^Mynameis(.*)$")publicvoidmy_name_is(Stringname)designer.variable("username",name);

@When("^Isayhello.*$")publicvoidsay_hello()designer.send(echoEndpoint).messageType(MessageType.PLAINTEXT).payload("Hello,mynameis$username!");

@When("^Isaygoodbye.*$")publicvoidsay_goodbye()designer.send(echoEndpoint).messageType(MessageType.PLAINTEXT).payload("Goodbyefrom$username!");

@Then("^theserviceshouldreturn:\"([^\"]*)\"$")publicvoidverify_return(finalStringbody)designer.receive(echoEndpoint).messageType(MessageType.PLAINTEXT).payload("Youjustsaid:"+body);

AsyoucanseeweusedSpringautowiringmechanismfortheechoEndpointfieldinthestepdefinition.Alsobesuretodefinethe@ContextConfigurationannotationonthestepdefinition.TheCucumberSpringsupportloadstheSpringapplicationcontextandtakescareondependencyinjection.WeusetheCitrusCitrusSpringConfigJavaconfigurationbecausethisisthemainentranceforCitrustestcases.Youcanadd

CitrusReferenceGuide

408Cucumber

Page 409: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

custombeansandfurtherSpringrelatedconfigurationtothisSpringapplicationcontext.IfyouwanttoaddmorebeansforautowiringdosointheCitrusSpringconfiguration.Usuallythisisthedefaultcitrus-context.xmlwhichisautomaticallyloaded.

OfcourseyoucanalsouseacustomJavaSpringconfigurationclasshere.ButbesuretoalwaysimporttheCitrusSpringJavaconfigurationclasses,too.OtherwiseyouwillnotbeabletoexecutetheCitrusintegrationtestcapabilities.

Asusualweareabletouse@CitrusResourceannotatedTestDesignerfieldsforbuildingtheCitrusintegrationtestlogic.WiththisextensionyoucanusethefullSpringtestingpowerinyourtestsinparticulardependencyinjectionandalsotransactionmanagementfordatapersistancetests.

Citrusstepdefinitions

Citrusprovidessomeoutoftheboxpredefinedstepsfortypicalintegrationtestscenarios.Thesestepsarereadytouseinscenarioorfeaturestories.Youcanbasicallydefinesendandreceiveoperations.AsthesestepsarepredefinedinCitrusyoujustneedtowritefeaturestories.Thestepdefinitionswithgluetotestactionsarehandledautomatically.

Ifyouwanttoenablepredefinedstepssupportinyourtestyouneedtoincludethegluecodepackageinyourtestclasslikethis:

@RunWith(Cucumber.class)@CucumberOptions(glue="com.consol.citrus.cucumber.step.designer.core",plugin="com.consol.citrus.cucumber.CitrusReporter")publicclassMyFeatureIT

Insteadofwritingthegluecodeonourowninstepdefinitionclassesweincludethegluepackagecom.consol.citrus.cucumber.step.designer.core.ThisautomaticallyloadsallCitrusgluestepdefinitionsinthispackage.OnceyouhavedonethisyoucanusepredefinedstepsthataddCitrustestlogicwithouthavingtowriteanygluecodeinJavastepdefinitions.

OfcourseyoucanalsochoosetoincludetheTestRunnerstepdefinitionsbychoosingthegluepackagecom.consol.citrus.cucumber.step.runner.core.

@RunWith(Cucumber.class)

CitrusReferenceGuide

409Cucumber

Page 410: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

@CucumberOptions(glue="com.consol.citrus.cucumber.step.runner.core",plugin="com.consol.citrus.cucumber.CitrusReporter")publicclassMyFeatureIT

Followingbasicstepdefinitionsareincludedinthispackage:

Givenvariable[name]is"[value]"Givenvariables|[name1]|[value1]||[name2]|[value2]|

When<[endpoint-name]>sends"[message-payload]"Then<[endpoint-name]>shouldreceive(message-type)"[message-payload]"

When<[endpoint-name]>sends"""[message-payload]"""Then<[endpoint-name]>shouldreceive(message-type)"""[message-payload]"""

When<[endpoint-name]>receives(message-type)"[message-payload]"Then<[endpoint-name]>shouldsend"[message-payload]"

When<[endpoint-name]>receives(message-type)"""[message-payload]"""Then<[endpoint-name]>shouldsend"""[message-payload]"""

Onceagainitshouldbesaidthatthestepdefinitionsincludedinthispackageareloadedautomaticallyasgluecode.SoyoucanstarttowritefeaturestoriesinGherkinsyntaxthattriggerthepredefinedsteps.

Thereareseveraldefaultstepdefinitionsfordifferentaspectsofintegrationtesting.PleaseseethefollowingpackagesthatdefinedefaultstepsinCitrus:

Testdesignerpackages

com.consol.citrus.cucumber.step.designer.core

CitrusReferenceGuide

410Cucumber

Page 411: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

com.consol.citrus.cucumber.step.designer.httpcom.consol.citrus.cucumber.step.designer.dockercom.consol.citrus.cucumber.step.designer.selenium

Testrunnerpackages

com.consol.citrus.cucumber.step.runner.corecom.consol.citrus.cucumber.step.runner.httpcom.consol.citrus.cucumber.step.runner.dockercom.consol.citrus.cucumber.step.runner.selenium

InthefollowingsectionswehaveacloserlookatallpredefinedCitrusstepsandhowtheywork.

Variablesteps

AsyoualreadyknowCitrusisabletoworkwithtestvariablesthatholdimportantinformationduringatestsuchasidentifiersanddynamicvalues.ThepredefinedstepdefinitionsinCitrusareabletocreatenewtestvariables.

GivenvariablemessageTextis"Hello"

Thesyntaxofthispredefinedstepisprettyselfdescribing.Thestepinstructionfollowsthepattern:

Givenvariable[name]is"[value]"

Ifyoukeepthissyntaxinyourfeaturestorythepredefinedstepisactivatedforcreatinganewvariable.WealwaysusetheGivensteptocreatenewvariables.

Scenario:CreateVariablesGivenvariablemessageTextis"Hello"AndvariableoperationHeaderis"sayHello"

SowecanusetheAndkeywordtocreatemorethanonevariable.Evenmorecomfortableistheusageofdatatables:

Givenvariables|hello|Isayhello||goodbye|Isaygoodbye|

CitrusReferenceGuide

411Cucumber

Page 412: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Thisdatatablewillcreatethetestvariableforeachrow.ThisishowyoucaneasilycreatenewvariablesinyourCitrustest.Asusualthevariablesarereferencedinmessagepayloadsandheadersasplaceholdersfordynamicallyaddingcontent.

AddingvariablesisusuallydonewithinaScenarioblockinyourfeaturestory.ThismeansthatthetestvariableisusedinthisscenariowhichisexactlyoneCitrustestcase.CucumberBDDalsodefinesaBackgroundblockattheverybeginningofyourFeature.Wecanalsoplacevariablesinhere.ThismeansthatCucumberwillexecutethesestepsforallupcomingscenarios.Thetestvariableissotospeakglobalforthisfeaturestory.

Feature:Variables

Background:GivenvariablemessageTextis"Hello"

Scenario:DosomethingScenario:Dosomethingelse

ThatcompletesthevariablestepdefinitionsinCitrus.

Messagingsteps

IntheprevioussectionwehavelearnedhowtouseafirstpredefinedCitrusstep.NowwewanttocovermessagingstepsforsendingandreceivingmessagesinCitrus.Asusualwithpredefinedstepsyoudonotneedtowriteanygluecodeforthestepstotakeaction.ThestepsarealreadyincludedinCitrusjustusetheminyourfeaturestories.

Feature:Messagingfeatures

Background:GivenvariablemessageTextis"Hello"

Scenario:SendandreceiveplaintextWhen<echoEndpoint>sends"$messageText"Then<echoEndpoint>shouldreceiveplaintext"Youjustsaid:$messageText"

Ofcourseweneedtofollowthepredefinedsyntaxwhenwritingfeaturestoriesinordertotriggerapredefinedstep.Let'shaveacloserlookatthispredefinedsyntaxbyfurtherdescribingtheaboveexample.

CitrusReferenceGuide

412Cucumber

Page 413: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

FirstofallwedefineanewtestvariablewithGivenvariablemessageTextis"Hello".ThistellsCitrustocreateanewtestvariablenamedmessageTextwithrespectivevalue.Wecandothesameforsendingandreceivingmessageslikedoneinourtestscenario:

When<[endpoint-name]>sends"[message-payload]"

Thestepdefinitionrequirestheendpointcomponentnameandamessagepayload.ThepredefinedstepwillautomaticallyconfigureasendtestactionintheCitrustestasresult.

Then<[endpoint-name]>shouldreceive(message-type)"[message-payload]"

Thepredefinedreceivestepalsorequirestheendpoint-nameandmessage-payload.Asoptionalparameteryoucandefinethemessage-type.ThisisrequiredwhensendingmessagepayloadsotherthanXML.

ThiswayyoucanwriteCitrustestswithjustwritingfeaturestoriesinGherkinsyntax.Uptonowwehaveusedprettysimplemessagepayloadsinonsingleline.Ofcoursewecanalsousemultilinepayloadsinthestories:

Feature:Messagingfeatures

Background:GivenvariablemessageTextis"Hello"

Scenario:SendandreceiveWhen<echoEndpoint>sends"""<message><text>$messageText</text></message>"""Then<echoEndpoint>shouldreceive"""<message><text>$messageText</text></message>"""

AsyoucanseeweareabletousethesendandreceivestepswithmultilineXMLmessagepayloaddata.

Namedmessages

CitrusReferenceGuide

413Cucumber

Page 414: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

IntheprevioussectionwehavelearnedhowtouseCitruspredefinedstepdefinitionsforsendandreceiveoperations.Themessagepayloadhasbeenaddeddirectlytothestoriessofar.Butwhatiswithmessageheaderinformation?Wewanttospecifyacompletemessagewithpayloadandheader.Youcandothisbydefininganamedmessage.

Asusualwedemonstratethisinafirstexample:

Feature:Namedmessagefeature

Background:GivenmessageechoRequestAnd<echoRequest>payloadis"HimynameisCitrus!"And<echoRequest>headeroperationis"sayHello"

GivenmessageechoResponseAnd<echoResponse>payloadis"Hi,Citrushowareyoudoingtoday?"And<echoResponse>headeroperationis"sayHello"

Scenario:SendandreceiveWhen<echoEndpoint>sendsmessage<echoRequest>Then<echoEndpoint>shouldreceivemessage<echoResponse>

IntheBackgroundsectionweintroducenamedmessagesechoRequestandechoResponse.Thismakesuseofthenewpredefinedstepforaddingnamedmessage:

Givenmessage[message-name]

Oncethemessageisintroducedwithitsnamewecanusethemessageinfurtherconfigurationsteps.Youcanaddpayloadinformationandyoucanaddmultipleheaderstothemessage.Thenamedmessagethenisreferencedinsendandreceivestepsasfollows:

When<[endpoint-name]>sendsmessage<[message-name]>Then<[endpoint-name]>shouldreceivemessage<[message-name]>

ThestepsreferenceamessagebyitsnameechoRequestandechoResponse.

Asyoucanseethenamedmessagesareusedtodefinecompletemessageswithpayloadandheaderinformation.Ofcoursethenamedmessagescanbereferencedinmanyscenariosandsteps.Alsowithusageoftestvariablesinpayloadandheaderyou

CitrusReferenceGuide

414Cucumber

Page 415: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

candynmaicallyadjustthosemessagesineachstep.

Messagecreatorsteps

Intheprevioussectionwehavelearnedhowtousenamedmessagesaspredefinedstep.Thenamedmessagehasbeendefineddirectlyinthestoriessofar.ThemessagecreatorconceptmovesthistasktosomeJavaPOJO.Thiswayyouareabletoconstructmorecomplicatedmessagesforreuseinseveralscenariosandfeaturestories.

Asusualwedemonstratethisinafirstexample:

Feature:Messagecreatorfeatures

Background:Givenmessagecreatorcom.consol.citrus.EchoMessageCreatorAndvariablemessageTextis"Hello"Andvariableoperationis"sayHello"

Scenario:SendandreceiveWhen<echoEndpoint>sendsmessage<echoRequest>Then<echoEndpoint>shouldreceivemessage<echoResponse>

IntheBackgroundsectionweintroduceamessagecreatorEchoMessageCreatorinpackagecom.consol.citrus.Thismakesuseofthenewpredefinedstepforaddingmessagecreatorstothetest:

Givenmessagecreator[message-creator-name]

ThemessagecreatornamemustbethefullyqualifiedJavaclassnamewithpackageinformation.Oncethisisdonewecanusenamedmessagesinthesendandreceiveoperations:

When<[endpoint-name]>sendsmessage<[message-name]>Then<[endpoint-name]>shouldreceivemessage<[message-name]>

ThestepsreferenceamessagebyitsnameechoRequestandechoResponse.NowletshavealookatthemessagecreatorEchoMessageCreatorimplementationinordertoseehowthiscorrelatestoarealmessage.

publicclassEchoMessageCreator@MessageCreator("echoRequest")publicMessagecreateEchoRequest()

CitrusReferenceGuide

415Cucumber

Page 416: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

returnnewDefaultMessage(""+"$messageText"+"").setHeader("operation","$operation");

@MessageCreator("echoResponse")publicMessagecreateEchoResponse()returnnewDefaultMessage(""+"$messageText"+"").setHeader("operation","$operation");

AsyoucanseethemessagecreatorisaPOJOJavaclassthatdefinesoneormoremethodsthatareannotatedwith@MessageCreatorannotation.Theannotationrequiresamessagename.ThisishowCitruswillcorrelatemessagenamesinfeaturestoriestomessagecreatormethods.Themessagereturnedistheusedforthesendandreceiveoperationsinthetest.Themessagecreatorisreusableaccrossmultiplefeaturestoriesandscenarios.Inadditiontothatthecreatorisabletoconstructmessagesinamorepowerfulway.Forinstancethemessagepayloadcouldbeloadedfromfilesystemresources.

Echosteps

AnotherpredefinedstepdefinitioninCitrusisusedtoaddaechotestaction.Youcanusethefollowingstepinyourfeaturescenarios:

Feature:Echofeatures

Scenario:EchomessagesGivenvariablefoois"bar"Thenecho"Variablefoo=$foo"Thenecho"Todayiscitrus:currentDate()"

Thestepdefinitionrequiresfollowingpattern:

Thenecho"[message]"

Sleepsteps

Youcanaddsleeptestactionstothefeaturescenarios:

CitrusReferenceGuide

416Cucumber

Page 417: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Feature:Sleepfeatures

Scenario:SleepdefaulttimeThensleep

Scenario:SleepmillisecondstimeThensleep200ms

Thestepdefinitionrequiresoneofthefollowingpatterns:

ThensleepThensleep[time]ms

ThisaddsanewsleeptestactiontotheCitrustest.

Httpsteps

TheHttpstepsarespeciallydesignedforHttpclient-servercommunication.YoucanusethesestepsbyaddingfollowingpackagesasglueoptionsinyourCucumbertest:

com.consol.citrus.cucumber.step.(designer|runner).http

ThispackagecontainsHttpspecificstepsthatenableyoutosendandreceivemessagesviaHttpREST:

Feature:VotingHttpRESTAPI

Background:GivenURL:http://localhost:8080/rest/servicesGivenvariables|id|citrus:randomUUID()||title|DoyoulikeMondays?||options|["name":"yes","votes":0,"name":"no","votes":0]||report|true|

Scenario:ClearvotinglistWhensendDELETE/votingThenreceivestatus200OK

Scenario:GetemptyvotinglistGivenAccept:application/jsonWhensendGET/votingThenResponse:[]Andreceivestatus200OK

Scenario:Createvoting

CitrusReferenceGuide

417Cucumber

Page 418: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

GivenRequest:""""id":"$id","title":"$title","options":$options,"report":$report"""AndContent-Type:application/jsonWhensendPOST/votingThenreceivestatus200OK

Scenario:GetvotinglistWhensendGET/votingThenvalidate$.size()is1Thenvalidate$..titleis$titleThenvalidate$..reportis$reportAndreceivestatus200OK

ThefeaturescenariosusedefaultHttpstepstosendrequestswithdifferentmethods(GET,POST,PUT,DELETE)andreceivestatusresponses(Http200OK).Pleaseexplorethedefaultstepdefinitionsintherespectivepackagetogetadetailedunderstandingonhowtousethoseinyourfeaturespecification.

Dockersteps

Dockerstepsaccesscontainersandbuildimages.BydefaultthestepstrytofindavalidaDockerClientcomponentintheSpringapplicationcontextconfiguration.Youcanusethestepsinfeaturespecificationstomanagecontainerstates.

Feature:VotingDockerinfrastructure

Scenario:CheckcontainerdeploymentstateGivendocker-client"dockerClient"Thencontainer"voting-app"shouldberunningAndcontainer"message-broker"shouldberunning

Weareabletocheckthecontainerstaterunning.AllweneedistheDockercontainernameorid.WhatelsecanwedowithinthedefaultDockersteps?Wecanbuildnewimages:

Feature:Buildimages

Scenario:Buildvotingimage

CitrusReferenceGuide

418Cucumber

Page 419: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Givendocker-client"dockerClient"Whenbuildimage"voting:1.0.0"fromfile"scr/main/docker/Dockerfile"Thencreatecontainer"voting-app"from"voting:1.0.0"Andcontainer"voting-app"shouldberunning

ThisishowwecanuseDockercommandsinCucumberfeaturespecificationswithCitrusdefaultstepdefinitions.AlldefaultstepdefinitionsforDockerarelocatedinpackage

com.consol.citrus.cucumber.step.(designer|runner).docker

Seleniumsteps

SeleniumisawidelyusedUIautomationframeworkwherebrowseruserinteractionsaresimulated.WecanusedefaultSeleniumstepsinthefeaturespecificationsinordertoaccessSeleniumcommandsinourtests.

Feature:Votinguserinterface

Background:GivenuserstartsbrowserAndusernavigatesto"http://localhost:8080"

Scenario:WelcomepageThenpageshoulddisplaylinkwithlink-text="Runapplication"

Scenario:StartapplicationWhenuserclickslinkwithlink-text="Runapplication"Andsleep500msThenpageshoulddisplayheadingwithtag-name="h1"having|text|Votinglist|

Andpageshoulddisplaylinkwithlink-text="Novotingfound"Andpageshoulddisplayformwithid="new-voting"having|tag-name|form||attribute|method="post"|

Scenario:AddvotingGivenusernavigatesto"http://localhost:8080/voting"Whenusersetstext"Doyoulikeburgers?"toinputwithid="title"Anduserclicksbuttonwithid="submitNew"Andsleep500msThenpageshoulddisplayelementwithlink-text="Doyoulikeburgers?"

CitrusReferenceGuide

419Cucumber

Page 420: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

WiththepredefinedCucumberstepsforSeleniumweareabletointeractwiththebrowser.Forinstancewecanclickbuttons,verifypageobjectsandnavigatetodifferentpages.

AlltheseSeleniumstepsarelocatedinpackage:

com.consol.citrus.cucumber.step.(designer|runner).selenium

TheSeleniumbrowserisautomaticallypickedfromtheSpringbeanapplicationcontextconfigurationinCitrus.HereyoucandecidewhichSeleniumWebDrivertouseduringthetests.Alsoyoucaninstantiatewebpageinstancesandcallpageactionsandvalidationsteps:

publicclassVotingListPageimplementsWebPage,PageValidator<VotingListPage>

@FindBy(tagName="h1")privateWebElementheading;

@FindBy(id="new-voting")privateWebElementnewVotingForm;

/***Submitsnewvoting.*@paramtitle*@paramoptions*/publicvoidsubmit(Stringtitle,Stringoptions)newVotingForm.findElement(By.id("title")).sendKeys(title);if(StringUtils.hasText(options))newVotingForm.findElement(By.id("options")).sendKeys(options.replaceAll(":","\n"

newVotingForm.submit();

@Overridepublicvoidvalidate(VotingListPagewebPage,SeleniumBrowserbrowser,TestContextcontext)Assert.assertEquals("Votinglist",heading.getText());

Thispageobjectdefineselementsandactionsonthatpagethatarecallableinourfeaturespecification.

Feature:Votingpages

CitrusReferenceGuide

420Cucumber

Page 421: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Background:Givenpage"welcomePage"com.consol.citrus.demo.voting.selenium.pages.WelcomePageGivenpage"votingListPage"com.consol.citrus.demo.voting.selenium.pages.VotingListPage

Scenario:WelcomepageWhenuserstartsbrowserAndusernavigatesto"http://localhost:8080"ThenpagewelcomePageshouldvalidate

Scenario:StartapplicationWhenusernavigatesto"http://localhost:8080"AndpagewelcomePageperformsstartAppAndsleep500msThenpagevotingListPageshouldvalidate

Scenario:AddvotingGivenusernavigatesto"http://localhost:8080/voting"WhenpagevotingListPageperformssubmitwitharguments|Doyoulikepizza?|Andsleep500msThenpageshoulddisplayelementwithlink-text="Doyoulikepizza?"AndpagevotingListPageshouldvalidate

Scenario:AddvotingwithoptionsGivenusernavigatesto"http://localhost:8080/voting"WhenpagevotingListPageperformssubmitwitharguments|Whatisyourfavoritecolor?||red:green:blue|Andsleep500msThenpageshoulddisplayelementwithlink-text="Whatisyourfavoritecolor?"AndpagevotingListPageshouldvalidate

Thepageobjectsgetinstantiatedanddependencyinjectionmakessurethatwebelementsandotherresourcesarepassedtothepageobject.Thenactionmethodcanperformaswellasvalidationtaskscanvalidatethepagestate.

CitrusReferenceGuide

421Cucumber

Page 422: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ZookeepersupportCitrusprovidesconfigurationcomponentsandtestactionsforinteractingwithZookeeper.TheCitrusZookeeperclientcomponentexecutescommandslikecreate-node,checknode-exists,delete-node,getnode-dataorsetnode-data.AsauseryoucanexecuteZookeepercommandsaspartofaCitrustestandvalidatepossiblecommandresults.

NoteTheZookeepertestcomponentsinCitrusarekeptinaseparateMavenmodule.IfnotalreadydonesoyouhavetoincludethemoduleasMavendependencytoyourproject

<dependency><groupId>com.consol.citrus</groupId><artifactId>citrus-zookeeper</artifactId><version>2.7.1</version></dependency>

Citrusprovidesa"citrus-zookeeper"configurationnamespaceandschemadefinitionforZookeeperrelatedcomponentsandactions.IncludethisnamespaceintoyourSpringconfigurationinordertousetheCitruszookeeperconfigurationelements.ThenamespaceURIandschemalocationareaddedtotheSpringconfigurationXMLfileasfollows.

<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:citrus-zookeeper="http://www.citrusframework.org/schema/zookeeper/config"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/zookeeper/confighttp://www.citrusframework.org/schema/zookeeper/config/citrus-zookeeper-config.xsd">

[...]

</beans>

AfterthatyouareabletousecustomizedCitrusXMLelementsinordertodefinetheSpringbeans.

CitrusReferenceGuide

422Zookeeper

Page 423: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Zookeeperclient

BeforeyoucaninteractwithaZookeeperserveryouhavetoconfiguretheZookeeperclient.Asampleconfigurationisprovidedbelowdescribingtheconfigurationoptionsavailable:

<citrus-zookeeper:clientid="zookeeperClient"url="http://localhost:21118"timeout="2000"/>

ThisisatypicalclientconfigurationforconnectingtoaZookeeperserver.Nowyouareabletoexecuteseveralcommands.ThesecommandswillbesenttotheZookeeperserverforexecution.

Zookeepercommands

SeebelowallavailableZookeepercommandsthataCitrusclientisabletoexecute.

info:Retrievesthecurrentstateoftheclientconnectioncreate:CreatesaznodeinaspecifiedpathoftheZooKeepernamespacedelete:DeletesaznodefromaspecifiedpathoftheZooKeepernamespaceexists:Checksifaznodeexistsinthepathchildren:Getsalistofchildrenofaznodeget:Getsthedataassociatedwithaznodeset:Sets/writesdataintothedatafieldofaznode

BeforeweseesomeofthesecommandsinactionwehavetoaddanewtestnamespacetoourtestcasewhenusingtheXMLDSL.

<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:zookeeper="http://www.citrusframework.org/schema/zookeeper/testcase"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/zookeeper/testcasehttp://www.citrusframework.org/schema/zookeeper/testcase/citrus-zookeeper-testcase.xsd"

[...]

</beans>

CitrusReferenceGuide

423Zookeeper

Page 424: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

WeaddedtheZookeepernamespacewithprefixzookeeper:sonowwecanstarttoaddspecialtestactionstothetestcase:

XMLDSL

<zookeeper:createzookeeper-client="zookeeperClient"path="/$randomString"acl="OPEN_ACL_UNSAFE"<zookeeper:data>foo</zookeeper:data><zookeeper:expect><zookeeper:result><![CDATA["responseData":"path":"/$randomString"]]></zookeeper:result></zookeeper:expect></zookeeper:create>

<zookeeper:getzookeeper-client="zookeeperClient"path="/$randomString"><zookeeper:expect><zookeeper:result><![CDATA["responseData":"data":"foo"]]></zookeeper:result></zookeeper:expect></zookeeper:getData>

<zookeeper:setzookeeper-client="zookeeperClient"path="/$randomString"><zookeeper:data>bar</zookeeper:data></zookeeper:setData>

WhenusingtheJavaDSLwecandirectlyconfigurethecommandswithafluentAPI.

JavaDSLdesignerandrunner

@CitrusTestpublicvoidtestZookeeper()variable("randomString","citrus:randomString(10)");

zookeeper().create("/$randomString","foo")

CitrusReferenceGuide

424Zookeeper

Page 425: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

.acl("OPEN_ACL_UNSAFE").mode("PERSISTENT").validateCommandResult(newCommandResultCallback<ZooResponse>()@OverridepublicvoiddoWithCommandResult(ZooResponseresult,TestContextcontext)Assert.assertEquals(result.getResponseData().get("path"),context.replaceDynamicContentInString("/$randomString")););

zookeeper().get("/$randomString").validateCommandResult(newCommandResultCallback<ZooResponse>()@OverridepublicvoiddoWithCommandResult(ZooResponseresult,TestContextcontext)Assert.assertEquals(result.getResponseData().get("version"),0););

zookeeper().set("/$randomString","bar");

TheexamplesabovecreateanewznodeinZookeeperusingarandomStringaspath.WecangetandsetthedatawithexpectingandvalidatingtheresultoftheZookeeperserver.ThisisbasicallytheideaofintegratingZookepperoperationstoaCitrustest.ThisopensthegatetomanageZookeeperrelatedentitieswithinaCitrustest.WecanmanipulateandvalidatetheznodesontheZookeeperinstance.

Zookeeperkeepsitsnodesinahierarchicalstorage.Thismeansaznodecanhavechildrenandwecanaddandremovethose.InCitrusyoucangetallchildrenofaznodeandmanagethosewithinthetest:

XMLDSL

<zookeeper:createzookeeper-client="zookeeperClient"path="/$randomString/child1"acl="OPEN_ACL_UNSAFE"<zookeeper:data></zookeeper:data><zookeeper:expect><zookeeper:result><![CDATA["responseData":"path":"/$randomString/child1"]]></zookeeper:result></zookeeper:expect>

CitrusReferenceGuide

425Zookeeper

Page 426: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</zookeeper:create>

<zookeeper:createzookeeper-client="zookeeperClient"path="/$randomString/child2"acl="OPEN_ACL_UNSAFE"<zookeeper:data></zookeeper:data><zookeeper:expect><zookeeper:result><![CDATA["responseData":"path":"/$randomString/child2"]]></zookeeper:result></zookeeper:expect></zookeeper:create>

<zookeeper:childrenzookeeper-client="zookeeperClient"path="/$randomString"><zookeeper:expect><zookeeper:result><![CDATA["responseData":"children":["child1","child2"]]]></zookeeper:result></zookeeper:expect></zookeeper:children>

JavaDSLdesignerandrunner

zookeeper().create("/$randomString/child1","").acl("OPEN_ACL_UNSAFE").mode("PERSISTENT").validateCommandResult(newCommandResultCallback<ZooResponse>()@OverridepublicvoiddoWithCommandResult(ZooResponseresult,TestContextcontext)Assert.assertEquals(result.getResponseData().get("path"),context.replaceDynamicContentInString("/$randomString/child1")););

zookeeper().create("/$randomString/child2","").acl("OPEN_ACL_UNSAFE").mode("PERSISTENT").validateCommandResult(newCommandResultCallback<ZooResponse>()

CitrusReferenceGuide

426Zookeeper

Page 427: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

@OverridepublicvoiddoWithCommandResult(ZooResponseresult,TestContextcontext)Assert.assertEquals(result.getResponseData().get("path"),context.replaceDynamicContentInString("/$randomString/child2")););

zookeeper().children("/$randomString").validateCommandResult(newCommandResultCallback<ZooResponse>()@OverridepublicvoiddoWithCommandResult(ZooResponseresult,TestContextcontext)Assert.assertEquals(result.getResponseData().get("children").toString(),"[child1,child2]"););

CitrusReferenceGuide

427Zookeeper

Page 428: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

SpringRestdocssupportSpringRestdocsprojecthelpstoeasilygenerateAPIdocumentationforRESTfulservices.WhilemessagesareexchangedtheRestdocslibrarygeneratesrequest/responsesnippetsandAPIdocumentation.YoucanaddtheSpringRestdocsdocumentationtotheCitrusclientcomponentsforHttpandSOAPendpoints.

NoteTheSpringRestdocssupportcomponentsinCitrusarekeptinaseparateMavenmodule.IfnotalreadydonesoyouhavetoincludethemoduleasMavendependencytoyourproject

<dependency><groupId>com.consol.citrus</groupId><artifactId>citrus-restdocs</artifactId><version>2.7.1</version></dependency>

ForeasyconfigurationCitrushascreatedaseparatenamespaceandschemadefinitionforSpringRestdocsrelateddocumentation.IncludethisnamespaceintoyourSpringconfigurationinordertousetheCitrusRestdocsconfigurationelements.ThenamespaceURIandschemalocationareaddedtotheSpringconfigurationXMLfileasfollows.

<spring:beansxmlns:spring="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://www.citrusframework.org/schema/cucumber/testcase"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/restdocs/confighttp://www.citrusframework.org/schema/restdocs/config/citrus-restdocs-config.xsd">

[...]

</spring:beans>

AfterthatyouareabletousecustomizedCitrusXMLelementsinordertodefinetheSpringbeans.

SpringRestdocsusingHttp

CitrusReferenceGuide

428Restdocs

Page 429: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

FirstofallweconcentrateonaddingtheSpringRestdocsfeaturetoHttpclientcommunication.ThenextsampleconfigurationusesthenewSpringRestdocscomponentsinCitrus:

<citrus-restdocs:documentationid="restDocumentation"output-directory="test-output/generated-snippets"identifier="rest-docs/method-name"/>

Theabovecomponentaddsanewdocumentationconfiguration.Behindthescenesthecomponentcreatesanewrestdocsconfigurerandaclientinterceptor.Wecanreferencethenewrestdocscomponentincitrus-httpclientcomponentslikethis:

<citrus-http:clientid="httpClient"request-url="http://localhost:8080/test"request-method="POST"interceptors="restDocumentation"/>

TheSpringRestdocsdocumentationcomponentactsasaclientinterceptor.EverytimetheclientcomponentisusedtosendandreceiveamessagetherestdocsinterceptorwillautomaticallycreateitsAPIdocumentation.Theconfigurationidentifierattributedescribestheoutputformatrest-docs/method-namewhichresultsinafolderlayoutlikethis:

test-output|-rest-docs|-test-a|-curl-request.adoc|-http-request.adoc|-http-response.adoc|-test-b|-curl-request.adoc|-http-request.adoc|-http-response.adoc|-test-c|-curl-request.adoc|-http-request.adoc|-http-response.adoc

TheexampleaboveistheresultofthreetestcaseseachofthemperformingaclientHttprequest/responsecommunication.Eachtestmessageexchangeisdocumentedwithseparatefiles:

CitrusReferenceGuide

429Restdocs

Page 430: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

curl-request.adoc

[source,bash]----$curl'http://localhost:8080/test'-i-XPOST-H'Accept:application/xml'-H'CustomHeaderId:123456789'-H'Content-Type:application/xml;charset=UTF-8'-H'Accept-Charset:utf-8'-d'>testRequestMessage>>text>HelloHttpServer>/text>>/testRequestMessage>'----

Thecurlfilerepresentstheclientrequestascurlcommandandcanbeseenasasampletoreproducetherequest.

http-request.adoc

[source,http,options="nowrap"]----POST/testHTTP/1.1Accept:application/xmlCustomHeaderId:123456789Content-Type:application/xml;charset=UTF-8Content-Length:118Accept-Charset:utf-8Host:localhost

>testRequestMessage>>text>HelloHttpServer>/text>>/testRequestMessage>----

Thehttp-request.adocfilerepresentsthesentmessagedatafortheclientrequest.Therespectivehttp-response.adocrepresentstheresponsethatwassenttotheclient.

http-response.adoc

[source,http,options="nowrap"]----HTTP/1.1200OKDate:Tue,07Jun201612:10:46GMTContent-Type:application/xml;charset=UTF-8Accept-Charset:utf-8Content-Length:122Server:Jetty(9.2.15.v20160210)

>testResponseMessage>>text>HelloCitrus!>/text>>/testResponseMessage>

CitrusReferenceGuide

430Restdocs

Page 431: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

----

Nicework!WehaveautomaticallycreatedsnippetsfortheRESTfulAPIbyjustaddingtheinterceptortotheCitrusclientcomponent.SpringRestdocscomponentscanbecombinedmanually.Seethenextconfigurationthatusesthisapproach.

<citrus-restdocs:configurerid="restDocConfigurer"output-directory="test-output/generated-snippets"<citrus-restdocs:client-interceptorid="restDocClientInterceptor"identifier="rest-docs/method-name"

<util:listid="restDocInterceptors"><refbean="restDocConfigurer"/><refbean="restDocClientInterceptor"/></util:list>

<citrus-http:clientid="httpClient"request-url="http://localhost:8080/test"request-method="POST"interceptors="restDocInterceptors"/>

Whatexactlyisthedifferencetothecitrus-restdocs:documentationthatwehaveusedbefore?Ingeneralthereisnodifference.Bothconfigurationsareidenticalinitsoutcome.Whyshouldsomeoneusethesecondapproachthen?Itismoreverboseasweneedtoalsodefinealistofinterceptors.Theansweriseasy.Ifyouwanttocombinetherestdocsinterceptorswithotherclientinterceptorsinalistthenyoushouldusethemanualcombinationapproach.Wecanaddbasicauthenticationinterceptorsforinstancetothelistofinterceptorsthen.Themorecomfortablecitrus-restdocs:documentationcomponentonlysupportsexclusiverestdocsinterceptors.

SpringRestdocsusingSOAP

YoucanusetheSpringRestdocsfeaturesalsoforSOAPclientsinCitrus.ThisisacontroversyideaasSOAPendpointsaredifferenttoRESTfulconcepts.ButattheendSOAPHttpcommunicationisHttpcommunicationwithrequestandresponsemessages.Whyshouldwemissoutthefantasticdocumentationfeatureherejustbecauseofideologyreasons.

TheconceptofaddingtheSpringRestdocsdocumentationasinterceptortotheclientisstillthesame.

<citrus-restdocs:documentationid="soapDocumentation"

CitrusReferenceGuide

431Restdocs

Page 432: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

type="soap"output-directory="test-output/generated-snippets"identifier="soap-docs/method-name"/>

Wehaveaddedatypesettingwithvaluesoap.Andthatisbasicallyallweneedtodo.NowCitrusknowsthatwewouldliketoadddocumentationforaSOAPclient:

<citrus-ws:clientid="soapClient"request-url="http://localhost:8080/test"interceptors="soapDocumentation"/>

FollowingfromthatthesoapClientisenabledtogenerateSpringRestdocsdocumentationforeachrequest/response.ThegeneratedsnippetsthendorepresenttheSOAPrequestandresponsemessages.

http-request.adoc

[source,http,options="nowrap"]----POST/testHTTP/1.1SOAPAction:"test"Accept:application/xmlCustomHeaderId:123456789Content-Type:application/xml;charset=UTF-8Content-Length:529Accept-Charset:utf-8Host:localhost

>SOAP-ENV:Envelopexmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">>SOAP-ENV:Header>>Operationxmlns="http://citrusframework.org/test">sayHello>/Operation>>/SOAP-ENV:Header>>SOAP-ENV:Body>>testRequestMessage>>text>HelloHttpServer>/text>>/testRequestMessage>>/SOAP-ENV:Body>>/SOAP-ENV:Envelope>----

http-response.adoc

[source,http,options="nowrap"]----HTTP/1.1200OK

CitrusReferenceGuide

432Restdocs

Page 433: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Date:Tue,07Jun201612:10:46GMTContent-Type:application/xml;charset=UTF-8Accept-Charset:utf-8Content-Length:612Server:Jetty(9.2.15.v20160210)

>SOAP-ENV:Envelopexmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">>SOAP-ENV:Header>>Operationxmlns="http://citrusframework.org/test">sayHello>/Operation>>/SOAP-ENV:Header>>SOAP-ENV:Body>>testResponseMessage>>text>HelloCitrus!>/text>>/testResponseMessage>>/SOAP-ENV:Body>>/SOAP-ENV:Envelope>----

Thefilenamesarestillusinghttp-requestandhttp-responsebutthecontentisclearlytheSOAPrequest/responsemessagedata.

SpringRestdocsinJavaDSL

HowcanweuseSpringRestdocsinJavaDSL?OfcoursewehavespecialsupportinCitrusJavaDSLfortheSpringRestdocsconfiguration,too.

JavaDSL

publicclassRestDocConfigurationITextendsTestNGCitrusTestDesigner

@AutowiredprivateTestListenerstestListeners;

privateHttpClienthttpClient;

@BeforeClasspublicvoidsetup()CitrusRestDocConfigurerrestDocConfigurer=CitrusRestDocsSupport.restDocsConfigurer(newManualRestDocumentation("target/generated-snippets"));RestDocClientInterceptorrestDocInterceptor=CitrusRestDocsSupport.restDocsInterceptor("rest-docs/method-name");

httpClient=CitrusEndpoints.http().client().requestUrl("http://localhost:8073/test").requestMethod(HttpMethod.POST).contentType("text/xml").interceptors(Arrays.asList(restDocConfigurer,restDocInterceptor)).build();

CitrusReferenceGuide

433Restdocs

Page 434: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

testListeners.addTestListener(restDocConfigurer);

@Test@CitrusTestpublicvoidtestRestDocs()http().client(httpClient).send().post().payload("<testRequestMessage>"+"<text>HelloHttpServer</text>"+"</testRequestMessage>");

http().client(httpClient).receive().response(HttpStatus.OK).payload("<testResponseMessage>"+"<text>HelloTestFramework</text>"+"</testResponseMessage>");

ThemechanismisquitesimilartotheXMLconfiguration.WeaddtheRestdocsconfigurerandinterceptortothelistofinterceptorsfortheHttpclient.Ifwedothisallclientcommunicationisautomaticallydocumented.TheCitrusJavaDSLprovidessomeconvenientconfigurationmethodsinclassCitrusRestDocsSupportforcreatingtheconfigurerandinterceptorobjects.

NoteTheconfigurermustbeaddedtothelistoftestlisteners.Thisisamandatorystepinordertoenabletheconfigurerfordocumentationpreparationsbeforeeachtest.Otherwisewewouldnotbeabletogenerateproperdocumentation.IfyouareusingtheXMLconfigurationthisisdoneautomaticallyforyou.

CitrusReferenceGuide

434Restdocs

Page 435: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

SeleniumsupportSeleniumisaverypopulartoolfortestinguserinterfaceswithbrowserautomation.CitrusisabletointegratewiththeSeleniumJavaAPIinordertoexecuteSeleniumcommands.

NoteTheSeleniumtestcomponentsinCitrusarekeptinaseparateMavenmodule.IfnotalreadydonesoyouhavetoincludethemoduleasMavendependencytoyourproject

<dependency><groupId>com.consol.citrus</groupId><artifactId>citrus-selenium</artifactId><version>2.7.1</version></dependency>

Citrusprovidesa"citrus-selenium"configurationnamespaceandschemadefinitionforSeleniumrelatedcomponentsandactions.IncludethisnamespaceintoyourSpringconfigurationinordertousetheCitrusSeleniumconfigurationelements.ThenamespaceURIandschemalocationareaddedtotheSpringconfigurationXMLfileasfollows.

<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:citrus-selenium="http://www.citrusframework.org/schema/selenium/config"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/selenium/confighttp://www.citrusframework.org/schema/selenium/config/citrus-selenium-config.xsd">

[...]

</beans>

AfterthatyouareabletousecustomizedCitrusXMLelementsinordertodefinetheSpringbeans.

Seleniumbrowser

CitrusReferenceGuide

435Selenium

Page 436: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Seleniumusesbrowserautomationinordertosimulatetheuserinteractwithwebapplications.YoucanconfiguretheSeleniumbrowserandwebdriverasSpringbean.

<citrus-selenium:browserid="seleniumBrowser"type="firefox"start-page="http://citrusframework.org"/>

TheSeleniumbrowsercomponentsupportsdifferentbrowsertypesforthecommonlyusedbrowsersoutinthewild.

htmlunitfirefoxsafarichromegooglechromeinternetexploreredgecustom

Htmlunitisthedefaultbrowsertypeandrepresentsaheadlessbrowserthatexecutedwithoutdisplayingthegraphicaluserinterface.IncaseyouneedatotallydifferentbrowseroryouneedtocustomizetheSeleniumwebdriveryoucanusethebrowserType="custom"incombinationwithawebdriverreference:

<citrus-selenium:browserid="mySeleniumBrowser"type="custom"web-driver="operaWebDriver"/>

<beanid="operaWebDriver"class="org.openqa.selenium.opera.OperaDriver"/>

NowCitrusisusingthecustomizedSeleniumwebdriverimplementation.

NoteWhenusingFirefoxasbrowseryoumayalsowanttosettheoptionalpropertiesfirefox-profileandversion.

<citrus-selenium:browserid="mySeleniumBrowser"type="firefox"firefox-profile="firefoxProfile"version="FIREFOX_38"start-page="http://citrusframework.org"/>

<beanid="firefoxProfile"class="org.openqa.selenium.firefox.FirefoxProfile"/>

CitrusReferenceGuide

436Selenium

Page 437: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

NowCitrusisabletoexecuteSeleniumoperationsasauser.

Seleniumactions

WehaveseveralCitrustestactionseachrepresentingaSeleniumcommand.TheseactionscanbepartofaCitrustestcase.AsaprerequisitewehavetoenabletheSeleniumspecifictestactionsinourXMLtestasfollows:

<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:selenium="http://www.citrusframework.org/schema/selenium/testcase"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/selenium/testcasehttp://www.citrusframework.org/schema/selenium/testcase/citrus-selenium-testcase.xsd"

[...]

</beans>

Weaddedaspecialseleniumnamespacewithprefixselenium:sonowwecanstarttoaddSeleniumtestactionstothetestcase:

XMLDSL

<testcasename="SeleniumCommandIT"><actions><selenium:startbrowser="webBrowser"/>

<selenium:navigatepage="http://localhost:8080"/>

<selenium:find><selenium:elementtag-name="h1"text="Welcome!"><selenium:styles><selenium:stylename="font-size"value="40px"/></selenium:styles></selenium:element></selenium:find>

<selenium:click><selenium:elementid="ok-button"/></selenium:click></actions></testcase>

CitrusReferenceGuide

437Selenium

Page 438: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

InthisverysimpleexamplewefirststarttheSeleniumbrowserinstance.AfterthatwecancontinuetouseSeleniumcommandswithoutbrowserattributeexplicitlyset.Citrusknowswhichbrowserinstanceiscurrentlyactiveandwillautomaticallyusethisopenedbrowserinstance.Nextinthisexamplewefindsomeelementonthedisplayedpagebyitstag-nameandtext.Wealsovalidatetheelementstylefont-sizetomeettheexpectedvalue40pxinthisstep.

Inadditiontothattheexampleperformsaclickoperationontheelementwiththeidok-button.Seleniumsupportselementfindoperationsondifferentproperties:

idfindselementbasedontheidattributenamefindselementbasedonthenameattributetag-namefindselementbasedonthetagnameclass-namefindselementbasedonthecssclassnamelink-textfindslinkelementbasedonthelink-textxpathfindselementbasedonXPathevaluationintheDOM

BasedonthatwecanexecuteseveralSeleniumcommandsinatestcaseandvalidatetheresultssuchaswebelements.

CitrussupportsthefollowingSeleniumcommandswithrespectivetestactions:

selenium:startStartthebrowserinstanceselenium:findFindselementoncurrentpageandvalidateselementpropertiesselenium:clickPerformsclickoperationonelementselenium:hoverPerformshoveroperationonelementselenium:navigateNavigatestonewpageurl(includinghistoryback,forwardandrefresh)selenium:set-inputFindsinputelementandsetsvalueselenium:check-inputFindscheckboxelementandsets/unsetsvalueselenium:dropdown-selectFindsdropdownelementandselectssingleormultiplevalue/sselenium:pageInstantiatepageobjectwithdependencyinjectionandexecutepageactionwithverificationselenium:openOpennewwindowselenium:closeClosewindowbygivennameselenium:switchSwitchfocustowindowwithgivennameselenium:wait-untilWaitforelementtobehiddenorvisibleselenium:alertAccesscurrentalertdialog(withactionaccessordismiss)selenium:screenshotMakesscreenshotofcurrentpage

CitrusReferenceGuide

438Selenium

Page 439: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

selenium:store-fileStorefiletotemporarybrowserdirectoryselenium:get-stored-fileGetsstoredfilefromtemporarybrowserdirectoryselenium:javascriptExecuteJavascriptcodeinbrowserselenium:clear-cacheClearbrowsercacheandallcookiesselenium:stopStopsthebrowserinstance

UptonowwehaveonlyusedtheCitrusXMLDSL.OfcourseallSeleniumcommandsarealsoavailableinJavaDSLasthenextexampleshows.

JavaDSL

@AutowiredprivateSeleniumBrowserseleniumBrowser;

@CitrusTestpublicvoidseleniumTest()selenium().start(seleniumBrowser);

selenium().navigate("http://localhost:8080");

selenium().find().element(By.id("header"));.tagName("h1").enabled(true).displayed(true).text("Welcome!").style("font-size","40px");

selenium().click().element(By.linkText("ClickMe!"));

NowletshaveacloserlookatthedifferentSeleniumtestactionssupportedinCitrus.

Start/stopbrowser

Youcanstartandstopthebrowserinstancewithatestaction.Thisinstantiatesanewbrowserwindowandprepareseverythingforinteractingwiththewebinterface.

XMLDSL

<selenium:startbrowser="seleniumBrowser"/>

<!--Dosomethinginbrowser-->

<selenium:stopbrowser="seleniumBrowser"/>

CitrusReferenceGuide

439Selenium

Page 440: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

JavaDSL

selenium().start(seleniumBrowser);

//dosomethinginbrowser

selenium().stop(seleniumBrowser);

AfterstartingabrowserinstanceCitruswillautomaticallyusethisverysamebrowserinstanceinallfurtherSeleniumactions.Thismechanismisbasedonatestvariable(selenium_browser)thatisautomaticallyset.Allothertestactionsareabletoloadthecurrentbrowserinstancebyreadingthistestvariablebeforeexecution.IncaseyouneedtoexplicitlyuseadifferentbrowserinstancethantheactiveinstanceyoucanaddthebrowserattributetoallSeleniumtestactions.

Note

Itisagoodideatostartandstopthebrowserinstancebeforeeachtestcase.Thismakessurethattestsarealsoexecutableinsinglerunanditalwayssetsupanewbrowserinstancesotestswillnotinfluenceeachother.

Find

Thefindelementtestactionsearchesforanelementonthecurrentpage.Theelementisspecifiedbyoneofthefollowingsettings:

idfindselementbasedontheidattributenamefindselementbasedonthenameattributetag-namefindselementbasedonthetagnameclass-namefindselementbasedonthecssclassnamelink-textfindslinkelementbasedonthelink-textxpathfindselementbasedonXPathevaluationintheDOM

Thefindelementactionwillautomaticallyfailincasethereisnosuchelementonthecurrentpage.Incasetheelementisfoundyoucanaddadditionalattributesandpropertiesforfurtherelementvalidation:

XMLDSL

<selenium:find><selenium:elementtag-name="h1"text="Welcome!"><selenium:styles><selenium:stylename="font-size"value="40px"/>

CitrusReferenceGuide

440Selenium

Page 441: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</selenium:styles></selenium:element></selenium:find>

<selenium:find><selenium:elementid="ok-button"text="Ok"enabled="true"displayed="true"><selenium:attributes><selenium:attributename="type"value="submit"/></selenium:attributes></selenium:element></selenium:find>

JavaDSL

selenium().find().element(By.tagName("h1")).text("Welcome!").style("font-size","40px");

selenium().find().element(By.id("ok-button")).tagName("button").enabled(true).displayed(true).text("Ok").style("color","red").attribute("type","submit");

Theexampleabovefindstheh1elementbyitstagnameandvalidatesthetextandcssstyleattributes.Secondlytheok-buttonisvalidatedwithexpectedenabled,displayed,text,styleandattributevalues.Theelementsmustbepresentonthecurrentpageandallexpectedelementpropertieshavetomatch.Otherwisethetestactionandthetestcaseisfailingwithvalidationerrors.

Click

Theactionperformsaclickoperationontheelement.

XMLDSL

<selenium:click><selenium:elementlink-text="ClickMe!"/></selenium:click>

JavaDSL

CitrusReferenceGuide

441Selenium

Page 442: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

selenium().click().element(By.linkText("ClickMe!"));

Hover

Theactionperformsahoveroperationontheelement.

XMLDSL

<selenium:hover><selenium:elementlink-text="FindMe!"/></selenium:hover>

JavaDSL

selenium().hover().element(By.linkText("FindMe!"));

Forminputactions

Thefollowingactionsareusedtoaccessforminputelementssuchastextfields,checkboxesanddropdownlists.

XMLDSL

<selenium:set-inputvalue="Citrus"><selenium:elementname="username"/></selenium:set-input>

<selenium:check-inputchecked="true"><selenium:elementxpath="//input[@type='checkbox']"/></selenium:check-input>

<selenium:dropdown-selectoption="happy"><selenium:elementid="user-mood"/></selenium:dropdown-select>

JavaDSL

selenium().setInput("Citrus").element(By.name("username"));selenium().checkInput(true).element(By.xpath("//input[@type='checkbox']"));

selenium().select("happy").element(By.id("user-mood"));

CitrusReferenceGuide

442Selenium

Page 443: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Theactionsaboveselectdropdownoptionsandsetuserinputontextfieldsandcheckboxes.Asusualtheformelementsareselectedbysomepropertiessuchasids,namesorxpathexpressions.

Pageactions

PageobjectsareawellknownpatternwhenusingSelenium.Thepageobjectsdefineelementsthatthepageisworkingwith.Inadditiontothatthepageobjectsdefineactionsthatcanbeexecutedfromoutside.Thisobjectorientedapproachforaccessingpagesandtheirelementsisaverygoodidea.Letshavealookatasamplepageobject.

publicclassUserFormPageimplementsWebPage

@FindBy(id="userForm")privateWebElementform;

@FindBy(id="username")privateWebElementuserName;

/***Setstheusername.*/publicvoidsetUserName(Stringvalue,TestContextcontext)userName.clear();userName.sendKeys(value);

/***Submitstheform.*@paramcontext*/publicvoidsubmit(TestContextcontext)form.submit();

AsyoucanseethepageobjectisaJavaPOJOthatimplementstheWebPageinterface.ThepagedefinesWebElementmembers.TheseareautomaticallyinjectedbyCitrusandSeleniumbasedontheFindByannotation.NowthetestcaseisabletoloadthatpageobjectandexecutesomeactionmethodsonthepagesuchassetUserNameorsubmit.

XMLDSL

<selenium:pagetype="com.consol.citrus.selenium.pages.UserFormPage"

CitrusReferenceGuide

443Selenium

Page 444: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

action="setUserName"><selenium:arguments><selenium:argument>Citrus</selenium:argument></selenium:arguments></selenium:page>

<selenium:pagetype="com.consol.citrus.selenium.pages.UserFormPage"action="submit"/>

JavaDSL

selenium().page(UserFormPage.class).argument("Citrus").execute("setUserName");

selenium().page(UserFormPage.class).execute("submit");

ThepageobjectclassisautomaticallyloadedandinstantiatedwithdependencyinjectionforallFindByannotatedwebelements.Afterthattheactionmethodisexecuted.TheactionmethodscanalsohavemethodparametersasseeninsetUserName.Thevalueparameterisautomaticallysetwhencallingthemethod.

MethodscanalsousetheoptionalparameterTestContext.Withthiscontextyoucanaccessthecurrenttestcontextwithalltestvariablesforinstance.Thismethodparametershouldalwaysbethelastparameter.

Pagevalidation

Wecanalsousepageobjectforvalidationpurpose.Thepageobjectisloadedandinstantiatedasdescribedinprevioussection.Thenthepagevalidatoriscalled.Thevalidatorperformsassertionsandvalidationoperationswiththepageobject.Letsseeasamplepagevalidator:

publicclassUserFormValidatorimplementsPageValidator<UserFormPage>

@Overridepublicvoidvalidate(UserFormPagewebPage,SeleniumBrowserbrowser,TestContextcontext)Assert.isTrue(webPage.getUserName()!=null);Assert.isTrue(StringUtils.hasText(webPage.getUserName().getAttribute("value")));

CitrusReferenceGuide

444Selenium

Page 445: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Thepagevalidatoriscalledwiththewebpageinstance,thebrowserandthetestcontext.Thevalidatorshouldassertpageobjectsandwebelementsforvalidationpurpose.Inatestcasewecancallthevalidatortovalidatethepage.

XMLDSL

<beanid="userFormValidator"class="com.consol.citrus.selenium.pages.UserFormValidator"/>

<selenium:pagetype="com.consol.citrus.selenium.pages.UserFormPage"action="validate"validator="userFormValidator"/>

JavaDSL

@AutowiredprivateUserFormValidatoruserFormValidator;

selenium().page(UserFormPage.class).execute("validate").validator(userFormValidator);

Insteadofusingaseparatevalidatorclassyoucanalsoputthevalidationmethodtothepageobjectitself.Thenpageobjectandvalidationisdonewithinthesameclass:

publicclassUserFormPageimplementsWebPage,PageValidator<UserFormPage>

@FindBy(id="userForm")privateWebElementform;

@FindBy(id="username")privateWebElementuserName;

/***Setstheusername.*/publicvoidsetUserName(Stringvalue,TestContextcontext)userName.clear();userName.sendKeys(value);

/***Submitstheform.*@paramcontext*/publicvoidsubmit(TestContextcontext)form.submit();

@Override

CitrusReferenceGuide

445Selenium

Page 446: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

publicvoidvalidate(UserFormPagewebPage,SeleniumBrowserbrowser,TestContextcontext)Assert.isTrue(userName!=null);Assert.isTrue(StringUtils.hasText(userName.getAttribute("value")));Assert.isTrue(form!=null);

XMLDSL

<selenium:pagetype="com.consol.citrus.selenium.pages.UserFormPage"action="validate"/>

JavaDSL

selenium().page(UserFormPage.class).execute("validate");

Wait

Sometimesitisrequiredtowaitforanelementtoappearordisappearonthecurrentpage.Thewaitactionwillwaitagiventimefortheelementstatustobevisibleorhidden.

XMLDSL

<selenium:waituntil="hidden"><selenium:elementid="info-dialog"/></selenium:wait>

JavaDSL

selenium().waitUntil().hidden().element(By.id("info-dialog"));

Theexamplewaitsfortheelementinfo-dialogtodisappear.Thetimetowaitis5000millisecondsbydefault.Youcansetthetimeoutontheaction.DuetoSeleniumlimitationstheminimumwaittimeis1000milliseconds.

Navigate

TheactionnavigatestoanewpageeitherbyusinganewrelativepathoracompletenewHttpURL.

CitrusReferenceGuide

446Selenium

Page 447: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

XMLDSL

<selenium:navigatepage="http://localhost:8080"/>

<selenium:navigatepage="help"/>

JavaDSL

selenium().navigate("http://localhost:8080");

selenium().navigate("help");

ThesampleabovedescribesanewpagewithnewHttpURL.Thebrowserwillnavigatetothisnewpage.AllfurtherSeleniumactionsareperformedonthisnewpage.ThesecondnavigationactionopenstherelativepagehelpsothenewpageURLishttp://localhost:8080/help.

Navigationisalwaysdoneontheactivebrowserwindow.Youcanmanagetheopenedwindowsasdescribedinnextsection.

Windowactions

Seleniumisabletomanagemultiplewindows.Soyoucanopen,closeandswichactivewindowsinaCitrustest.

XMLDSL

<selenium:open-windowname="my_window"/><selenium:switch-windowname="my_window"/><selenium:close-windowname="my_window"/>

JavaDSL

selenium().open().window("my_window");selenium().focus().window("my_window");selenium().close().window("my_window");

WhenanewwindowisopenedSeleniumcreatesawindowhandleforus.Thiswindowhandleissavedastestvariableusingagivenwindowname.Soafteropeningthewindowyoucanaccessthewindowbyitsnameinfurtheractions.Allupcoming

CitrusReferenceGuide

447Selenium

Page 448: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Seleniumactionswilltakeplaceinthisnewactivewindow.Ofcoursethetestactionswillfailassoonasthewindowwiththatgivennameismissing.Citrususesdefaultwindownamesthatareautomaticallyusedastestvariables:

selenium_active_windowtheactivewindowhandleselenium_last_windowthelastwindowhandlewhenswitchedtootherwindow

Alert

Weareabletoaccessthealertdialogonthecurrentpage.Citruswillvalidatethedisplayeddialogtextandacceptordismissofthedialog.

XMLDSL

<selenium:alertaccept="true"><selenium:alert-text>Hello!</selenium:alert-text></selenium:alert>

JavaDSL

selenium().alert().text("Hello!").accept();

Thealertdialogtextisvalidatedwhenexpectedtextisgivenonthetestaction.Theusercandecidetoacceptordismissthedialog.Afterthatthedialogshouldbeclosed.Incasethetestactionfailstofindanopenalertdialogthetestactionraisesruntimeerrorsandthetestwillfail.

Makescreenshot

Youcanexecutethisactionincaseyouwanttotakeascreenshotofthecurrentpage.Thisactiononlyworkswithbrowsersthatactuallydisplaytheuserinterface.TheactionwillnothaveanyeffectwhenexecutedwithHtmlunitwebdriverinheadlessmode.

XMLDSL

<selenium:screenshot/>

<selenium:screenshotoutput-dir="target"/>

JavaDSL

CitrusReferenceGuide

448Selenium

Page 449: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

selenium().screenhsot();

selenium().screenhsot("target");

Thetestactionhasanoptionalparameteroutput-dirwhichrepresentstheoutputdirectorywherethescreenshotissavedto.

Temporarystorage(Firefox)

ImportantThisactiononlyworkswithFirefoxwebdriver!Otherbrowsersarenotworkingwiththetemporarydownloadstorage.

Thebrowserusesatemporarystoragefordownloadedfiles.Wecanaccessthistemporarystorageduringatestcase.

XMLDSL

<selenium:store-filefile-path="classpath:download/file.txt"/><selenium:get-stored-filefile-name="file.txt"/>

JavaDSL

selenium().store("classpath:download/file.txt");selenium().getStored("file.txt");

Asyoucanseethetestcaseisabletostorenewfilestothetemporarybrowserstorage.Wehavetogivethefilepathasclasspathorfilesystempath.Whenreadingthetemporaryfilestorageweneedtospecifythefilenamethatwewanttoaccessinthetemporarystorage.Thetemporarystorageisnotcapableofsubdirectoriesallfilesarestoreddirectlytothestorageinonesingledirectory.

Incasethestoredfileisnotfoundbythatnamethetestactionfailswithrespectiveerrors.OntheotherhandwhenthefileisfoundintemporarystorageCitruswillautomaticallycreateanewtestvariableselenium_download_filewhichcontainsthefilenameasvalue.

Clearbrowsercache

Whenclearingthebrowsercacheallcookiesandtemporaryfileswillbedeleted.

XMLDSL

CitrusReferenceGuide

449Selenium

Page 450: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<selenium:clear-cache/>

JavaDSL

selenium().clearCache();

CitrusReferenceGuide

450Selenium

Page 451: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

DynamicendpointcomponentsEndpointsrepresentthecentralcomponentsinCitrustosendorreceiveamessageonsomedestination.UsuallyendpointsgetdefinedinthebasicCitrusSpringapplicationcontextconfigurationasSpringbeancomponents.Insomecasesthismightbeoverengineeringasthetesterjustwantstosendorreceiveamessage.Inparticularthisisdonewhendoingsanitychecksinserverendpointswhiledebuggingacertainscenario.

WithendpointcomponentsyouareabletocreatetheCitrusendpointforsendingandreceivingamessageattestruntime.ThereisnoadditionalconfigurationorSpringbeancomponentneeded.YoujustusetheendpointuriinaspecialnamingconventionandCitruswillcreatetheendpointforyou.Letusseeafirstexampleofthisscenario:

<testcasename="DynamicEndpointTest"><actions><sendendpoint="jms:Hello.Queue?timeout=10000"><message><payload>[...]</payload></message></send>

<receiveendpoint="jms:Hello.Response.Queue?timeout=5000"><message><payload>[...]</payload></message></receive></actions></testcase>

Asyoucanseetheendpointurijustgoesintothetestcaseactioninsubstitutiontotheusualendpointreferencename.InsteadofreferencingabeanidthatpointstothepreviouslyconfiguredCitrusendpointweusetheendpointuridirectly.Theendpointurishouldgiveallinformationtocreatetheendpointatruntime.Intheexampleaboveweuseakeywordjms:whichtellsCitrusthatweneedtocreateaJMSmessageendpoint.SecondlywegivetheJMSdestinationnameHello.Queuewhichisamandatorypartof

CitrusReferenceGuide

451Endpointcomponent

Page 452: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

theendpointuriwhenusingtheJMScomponent.Theoptionaltimeoutparametercompletedtheuri.CitrusisabletocreatetheJMSendpointatruntimesendingthemessagetothedefineddestinationviaJMS.

OfcoursethismechanismisnotlimitedtoJMSendpoints.WecanusealldefaultCitrusmessagetransportsintheendpointuri.Justpicktherightkeywordthatdefinesthemessagetransporttouse.Hereisalistofsupportedkeywords:

jms:CreatesaJMSendpointforsendingandreceivingmessagetoaqueueortopicchannel:CreatesachannelendpointforsendingandreceivingmessagesusinganinmemorySpringIntegrationmessagechannelhttp:CreatesaHTTPclientforsendingarequesttosomeserverURLsynchronouslywaitingfortheresponsemessagews:CreatesaWebSocketclientforsendingmessagestoorreceivingmessagesfromaWebSocketserversoap:CreatesaSOAPWebServiceclientthatsendaproperSOAPmessagetotheserverURLandwaitsforthesynchronousresponsetoarrivessh:Createsanewsshclientforpublishingacommandtotheservermail:orsmtp:CreatesanewmailclientforsendingamailmimemessagetoaSMTPservercamel:CreatesanewApacheCamelendpointforsendingandreceivingCamelexchangesbothtoandfromCamelroutes.vertx:oreventbus:CreatesanewVert.xinstancesendingandreceivingmessageswiththenetworkeventbusrmi:CreatesanewRMIclientinstancesendingandreceivingmessagesformethodinvocationonremoteinterfacesjmx:CreatesanewJMXclientinstancesendingandreceivingmessagestoandfromamanagedbeanserver.

Dependingonthemessagetransportwehavetoaddmandatoryparameterstotheendpointuri.IntheJMSexamplewehadtospecifythedestinationname.Themandatoryparametersarealwayspartoftheendpointuri.Optionalparameterscanbeaddedaskeyvaluepairstotheendpointuri.Theavailableparametersdependontheendpointkeywordthatyouhavechosen.Seetheseexampleendpointuriexpressions:

jms:queuename?connectionFactory=specialConnectionFactory&timeout=10000jms:topic:topicname?connectionFactory=topicConnectionFactoryjms:sync:queuename?connectionFactory=specialConnectionFactory&pollingInterval=100&replyDestination=myReplyDestination

channel:channelName

CitrusReferenceGuide

452Endpointcomponent

Page 453: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

channel:sync:channelNamechannel:channelName?timeout=10000&channelResolver=myChannelResolver

http:localhost:8088/testhttp://localhost:8088/testhttp:localhost:8088?requestMethod=GET&timeout=10000&errorHandlingStrategy=throwsException&requestFactory=myRequestFactoryhttp://localhost:8088/test?requestMethod=DELETE&customParam=foo

websocket:localhost:8088/testwebsocket://localhost:8088/testws:localhost:8088/testws://localhost:8088/test

soap:localhost:8088/testsoap:localhost:8088?timeout=10000&errorHandlingStrategy=propagateError&messageFactory=myMessageFactory

mail:localhost:25000smtp://localhost:25000smtp://localhost?timeout=10000&username=foo&password=1234&mailMessageMapper=myMapper

ssh:localhost:2200ssh://localhost:2200?timeout=10000&strictHostChecking=true&user=foo&password=12345678

rmi://localhost:1099/someServicermi:localhost/someService&timeout=10000

jmx:rmi:///jndi/rmi://localhost:1099/someServicejmx:platform&timeout=10000

camel:direct:addresscamel:seda:addresscamel:jms:queue:someQueue?connectionFactory=myConnectionFactorycamel:activemq:queue:someQueue?concurrentConsumers=5&destination.consumer.prefetchSize=50camel:controlbus:route?routeId=myRoute&action=status

vertx:addressNamevertx:addressName?port=10105&timeout=10000&pubSubDomain=truevertx:addressName?vertxInstanceFactory=vertxFactory

Theoptionalparametersgetdirectlysetasendpointconfiguration.YoucanuseprimitivevaluesaswellasSpringbeanidreferences.CitruswillautomaticallydetectthetargetparametertypeandresolvethevaluetoaSpringbeanintheapplicationcontextifnecessary.IfyouusesomeunknownparameterCitruswillraiseanexceptionatruntimeastheendpointcouldnotbecreatedproperly.

CitrusReferenceGuide

453Endpointcomponent

Page 454: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Insynchronouscommunicationwehavetoreuseendpointcomponentsinordertoreceivesynchronousmessagesonreplydestinations.Thisisaproblemwhenusingdynamicendpointsastheendpointsgetcreatedatruntime.Citrususesacachingofendpointsthatgetcreatedatruntime.Followingfromthatwehavetousetheexactsameendpointuriinyourtestcaseinordertogetthecachedendpointinstance.Withthislittletricksynchronouscommunicationwillworkjustasitisdonewithstaticendpointcomponents.Havealookatthissampletest:

<testcasename="DynamicEndpointTest"><actions><sendendpoint="jms:sync:Hello.Sync.Queue"><message><payload>[...]</payload></message></send>

<receiveendpoint="jms:sync:Hello.Sync.Queue"><message><payload>[...]</payload></message></receive></actions></testcase>

Asyoucanseeweusedtheexactdynamicendpointuriinbothsendandreceiveactions.Citrusisthenabletoreusethesamedynamicendpointandthesynchronousreplywillbereceivedasexpected.Howeverthereuseofexactlythesameendpointurimightgetannoyingaswealsohavetocopyendpointuriparametersandsoon.

<testcasename="DynamicEndpointTest"><actions><sendendpoint="http://localhost:8080/HelloService?user=1234567"><message><payload>[...]</payload></message></send>

<receiveendpoint="http://localhost:8080/HelloService?user=1234567"><message><payload>

CitrusReferenceGuide

454Endpointcomponent

Page 455: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

[...]</payload></message></receive></actions></testcase>

Wehavetousetheexactsameendpointuriwhenreceivingthesynchronousserviceresponse.Thisisnotverystraightforward.ThisiswhyCitrusalsosupportsdynamicendpointnames.WithaspecialendpointuriparametercalledendpointNameyoucannamethedynamicendpoint.Inacorrespondingreceiveactionyoujustusetheendpointnameasreferencewhichmakeslifemoreeasy:

<testcasename="DynamicEndpointTest"><actions><sendendpoint="http://localhost:8080/HelloService?endpointName=myHttpClient"><message><payload>[...]</payload></message></send>

<receiveendpoint="http://localhost?endpointName=myHttpClient"><message><payload>[...]</payload></message></receive></actions></testcase>

Sowecanreferencethedynamicendpointwiththegivenname.TheinternalendpointNameuriparameterisautomaticallyremovedbeforesendingoutmessages.OnceagainthedynamicendpointurimechanismprovidesafastwaytowritetestcasesinCitruswithlessconfiguration.ButyoushouldconsidertousethestaticendpointcomponentsdefinedinthebasicSpringbeanapplicationcontextforendpointsthatareheavilyreusedinmultipletestcases.

CitrusReferenceGuide

455Endpointcomponent

Page 456: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

EndpointadapterEndpointadapterhelptocustomizethebehaviorofaCitrusserversuchasHTTPorSOAPwebservers.AstheserversgetstartedwiththeCitruscontexttheyarereadytoreceiveincomingclientrequests.Nowtherearedifferentwaystoprocesstheseincomingrequestsandtoprovideaproperresponsemessage.Bydefaulttheserverwillforwardtheincomingrequesttoainmemorymessagechannelwhereatestcanreceivethemessageandprovideasynchronousresponse.Thismessagechannelhandlingisdoneautomaticallybehindthescenessothetesterdoesnotcareaboutthesethings.Thetesterjustusestheserverdirectlyasendpointreferenceinthetestcase.Thisisthedefaultbehaviour.InadditiontothatyoucandefinecustomendpointadaptersontheCitrusserverinordertochangethisdefaultbehavior.

Yousetthecustomendpointadapterdirectlyontheserverconfigurationasfollows:

<citrus-http:serverid="helloHttpServer"port="8080"auto-start="true"endpoint-adapter="emptyResponseEndpointAdapter"resource-base="src/it/resources"/>

<citrus:empty-response-adapterid="emptyResponseEndpointAdapter"/>

Nowletushaveacloserlookattheprovidedendpointadapterimplementations.

Emptyresponseendpointadapter

Thisisthesimplestendpointadapteryoucanthinkof.ItsimplyprovidesanemptysuccessresponseusingtheHTTPresponsecode200.TheadapterdoesnotneedanyconfigurationsorpropertiesasitsimplyrespondswithanemptyHTTPresponse.

<citrus:empty-response-adapterid="emptyResponseEndpointAdapter"/>

Staticresponseendpointadapter

Thenextmorecomplexendpointadapterwillalwaysreturnastaticresponsemessage.

<citrus:static-response-adapterid="endpointAdapter"><citrus:payload>

CitrusReferenceGuide

456Endpointadapter

Page 457: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<![CDATA[<HelloResponsexmlns="http://www.consol.de/schemas/samples/sayHello.xsd"><MessageId>123456789</MessageId><CorrelationId>Cx1x123456789</CorrelationId><Text>HelloUser</Text></HelloResponse>]]></citrus:payload><citrus:header><citrus:elementname="http://www.consol.de/schemas/samplesh1:Operation"value="sayHello"/><citrus:elementname="http://www.consol.de/schemas/samplesh1:MessageId"value="123456789"/></citrus:header></citrus:static-response-adapter>

Theendpointadapterisconfiguredwithastaticmessagepayloadandstaticresponseheadervalues.Theresponsetotheclientisthereforealwaysthesame.YoucanadddynamicvaluesbyusingCitrusfunctionssuchasrandomStringorrandomNumber.Alsoweareabletousevaluesoftheactualrequestmessagethathastriggeredtheresponseadapter.Therequestisavailableviathelocalmessagestore.IncombinationwithXpathorJsonPathfunctionswecanmapvaluesfromtheactualrequest.

<citrus:static-response-adapterid="endpointAdapter"><citrus:payload><![CDATA[<HelloResponsexmlns="http://www.consol.de/schemas/samples/sayHello.xsd"><MessageId>citrus:randomNumber(10)</MessageId><CorrelationId>citrus:xpath(citrus:message(request.payload()),'/hello:HelloRequest/hello:CorrelationId')</CorrelationId><Text>HelloUser</Text></HelloResponse>]]></citrus:payload><citrus:header><citrus:elementname="http://www.consol.de/schemas/samplesh1:Operation"value="sayHello"/><citrus:elementname="http://www.consol.de/schemas/samplesh1:MessageId"value="citrus:randomNumber(10)"/></citrus:header></citrus:static-response-adapter>

CitrusReferenceGuide

457Endpointadapter

Page 458: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TheexampleabovemapstheCorrelationIdoftheHelloRequestmessagetotheresponsewithXpathfunction.Thelocalmessagestoreautomaticallyhasthemessagenamedrequeststoredsowecanaccessthepayloadwiththismessagename.

NoteXMLisnamespacespecificsoweneedtousethenamespaceprefixhellointheXpathexpression.ThenamespaceprefixshouldevaluatetoaglobalnamespaceentryintheglobalCitrusxpath-namespace.

Requestdispatchingendpointadapter

Theideabehindtherequestdispatchingendpointadapteristhattheincomingrequestsaredispatchedtoseveralotherendpointadapters.Thedecisionwhichendpointadaptershouldhandletheactualrequestisdonedependingonsomeadaptermapping.Themappingisdonebasedonthepayloadorheaderdataoftheincomingrequest.Amappingstrategyevaluatesamappingkeyusingtheincomingrequest.YoucanthinkofanXPathexpressionthatevaluatestothemappingkeyforinstance.Theendpointadapterthatmapstothemappingkeyisthencalledtohandletherequest.

Sotherequestdispatchingendpointadapterisabletodynamicallycallseveralotherendpointadaptersbasedontheincomingrequestmessageatruntime.Thisisverypowerful.ThenextexampleusestherequestdispatchingendpointadapterwithaXPathmappingkeyextractor.

<citrus:dispatching-endpoint-adapterid="dispatchingEndpointAdapter"mapping-key-extractor="mappingKeyExtractor"mapping-strategy="mappingStrategy"/>

<beanid="mappingStrategy"class="com.consol.citrus.endpoint.adapter.mapping.SimpleMappingStrategy"><propertyname="adapterMappings"><map><entrykey="sayHello"ref="helloEndpointAdapter"/></map></property></bean>

<beanid="mappingKeyExtractor"class="com.consol.citrus.endpoint.adapter.mapping.XPathPayloadMappingKeyExtractor"><propertyname="xpathExpression"value="//TestMessage/Operation/*"/></bean>

<citrus:static-response-adapterid="helloEndpointAdapter"><citrus:payload><![CDATA[<HelloResponse

CitrusReferenceGuide

458Endpointadapter

Page 459: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

xmlns="http://www.consol.de/schemas/samples/sayHello.xsd"><MessageId>123456789</MessageId><Text>HelloUser</Text></HelloResponse>]]></citrus:payload></citrus:static-response-adapter>

TheXPathmappingkeyextractorexpressiondecidesforeachrequestwhichmappingkeytouseinordertofindaproperendpointadapterthroughthemappingstrategy.Theendpointadaptersavailableintheapplicationcontextaremappedviatheirbeanid.Forinstanceanincomingrequestwithamatchingelement//TestMessage/Operation/sayHellowouldbehandledbytheendpointadapterbeanthatisregisteredinthemappingstrategyas"sayHello"key.TheavailableendpointadaptersareconfiguredinthesameSpringapplicationcontext.

Citrusprovidesseveraldefaultmappingkeyextractorimplementations.

HeaderMappingKeyExtractor:Readsaspecialheaderentryandusesitsvalueasmappingkey

SoapActionMappingKeyExtractor:Usesthesoapactionheaderentryasmappingkey

XPathPayloadMappingKeyExtractor:EvaluatesaXPathexpressionontherequestpayloadandusestheresultasmappingkey

Inadditiontothatweneedamappingstrategy.Citrusprovidesfollowingdefaultimplementations.

SimpleMappingStrategy:Simplekeyvaluemapwithendpointadapterreferences

BeanNameMappingStrategy:LoadstheendpointadapterSpringbeanwiththegivenidmatchingthemappingkey

ContextLoadingMappingStrategy:SameasBeanNameMappingStrategybutloadsaseparateapplicationcontextdefinedbyexternalfileresource

Channelendpointadapter

ThechannelconnectingendpointadapteristhedefaultadapterusedinallCitrusservercomponents.Indeedthisadapteralsoprovidesthemostflexibility.Thisadapterforwardsincomingrequeststoachanneldestination.Theadapteriswaitingforaproperresponse

CitrusReferenceGuide

459Endpointadapter

Page 460: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

onareplydestinationsynchronously.Withthechannelendpointcomponentsyoucanreadtherequestsonthechannelandprovideaproperresponseonthereplydestination.

<citrus:channel-endpoint-adapterid="channelEndpointAdapter"channel-name="inbound.channel"timeout="2500"/>

JMSendpointadapter

AnotherpowerfulendpointadapteristheJMSconnectingadapterimplementation.ThisadapterforwardsincomingrequeststoaJMSdestinationandwaitsforaproperresponseonareplydestination.AJMSendpointcanaccesstherequestsinternallyandprovideaproperresponseonthereplydestination.Sothisadapterisveryflexibletoprovideproperresponsemessages.

Thisspecialadaptercomeswiththecitrus-jmsmodule.SoyouhavetoaddthemoduleandthespecialXMLnamespaceforthismoduletoyourconfigurationfiles.TheMavenmoduleforcitrus-jmsgoestotheMavenPOMfileasnormalprojectdependency.Thecitrus-jmsnamespacegoestotheSpringbeanXMLconfigurationfileasfollows:

NoteCitrusprovidesa"citrus-jms"configurationnamespaceandschemadefinitionforJMSrelatedcomponentsandfeatures.IncludethisnamespaceintoyourSpringconfigurationinordertousetheCitrusJMSconfigurationelements.ThenamespaceURIandschemalocationareaddedtotheSpringconfigurationXMLfileasfollows.

<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:citrus-jms="http://www.citrusframework.org/schema/jms/config"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/jms/confighttp://www.citrusframework.org/schema/jms/config/citrus-jms-config.xsd">

[...]

</beans>

AfterthatyouareabletousetheadapterimplementationintheSpringbeanconfiguration.

CitrusReferenceGuide

460Endpointadapter

Page 461: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<citrus-jms:endpoint-adapterid="jmsEndpointAdapter"destination-name="JMS.Queue.Requests.In"reply-destination-name="JMS.Queue.Response.Out"connection-factory="jmsConnectionFactory"timeout="2500"/>

<beanid="jmsConnectionFactory"class="org.apache.activemq.ActiveMQConnectionFactory"><propertyname="brokerURL"value="tcp://localhost:61616"/></bean>

CitrusReferenceGuide

461Endpointadapter

Page 462: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

FunctionsThetestframeworkwillofferseveralfunctionsthatareusefulthroughoutthetestexecution.Thefunctionswillalwaysreturnastringvaluethatisreadyforuseasvariablevalueordirectlyinsideatextmessage.

Asetoffunctionsisusuallycombinedtoafunctionlibrary.Thelibraryhasaprefixthatwillidentifythefunctionsinsidethetestcase.Thedefaulttestframeworkfunctionlibraryusesadefaultprefix(citrus).Youcanwriteyourownfunctionlibraryusingyourownprefixinordertoextendthetestframeworkfunctionalitywheneveryouwant.

ThelibraryisbuiltintheSpringconfigurationandcontainsasetoffunctionsthatareofpublicuse.

<citrus:function-libraryid="testLibrary"prefix="foo:"><citrus:functionname="randomNumber">class="com.consol.citrus.functions.RandomNumberFunction"/><citrus:functionname="randomString">class="com.consol.citrus.functions.RandomStringFunction"/><citrus:functionname="customFunction">ref="customFunctionBean"/>...</citrus:function-library>

AsyoucanseethelibrarydefinesonetomanyfunctionseitherreferencedasnormalSpringbeanorbyitsimplementingJavaclassname.Citrusconstructsthelibraryandyouareabletousethefunctionsinyourtestcasewiththeleadinglibraryprefixjustlikethis:

foo:randomNumber()foo:randomString()foo:customFunction()

TipYoucanaddcustomfunctionimplementationsandcustomfunctionlibraries.Justuseacustomprefixforyourlibrary.ThedefaultCitrusfunctionlibraryusesthecitrus:prefix.Inthenextchaptersthedefaultfunctionsofferedbytheframeworkwillbedescribedindetail.

concat()

CitrusReferenceGuide

462Functions

Page 463: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Thefunctionwillcombineseveralstringtokenstoasinglestringvalue.Thismeansthatyoucancombineastatictextvaluewithavariablevalueforinstance.Afirstexampleshouldclarifytheusage:

<testcasename="concatFunctionTest"><variables><variablename="date"value="citrus:currentDate(yyyy-MM-dd)"/><variablename="text"value="HelloTestFramework!"/></variables><actions><echo><message>citrus:concat('Todayis:',$date,'right!?')</message></echo><echo><message>citrus:concat('Textis:',$text)</message></echo></actions></testcase>

Pleasedonotforgettomarkstatictextwithsinglequotesigns.Thereisnolimitationforstringtokenstobecombined.

citrus:concat('Text1','Text2','Text3',$text,'Text5',…,'TextN')

Thefunctioncanbeusedwherevervariablescanbeused.ForinstancewhenvalidatingXMLelementsinthereceiveaction.

<message><validatepath="//element/element"value="citrus:concat('Cx1x',$generatedId)"/></message>

substring()

Thefunctionwillhavethreeparameters.

1. Stringtoworkon2. Startingindex3. Endindex(optional)

Letushavealookatasimpleexampleforthisfunction:

CitrusReferenceGuide

463Functions

Page 464: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<echo><message>citrus:substring('HelloTestFramework',6)</message></echo><echo><message>citrus:substring('HelloTestFramework',0,5)</message></echo>

Functionoutput:

TestFrameworkHello

stringLength()

Thefunctionwillcalculatethenumberofcharactersinastringrepresentationandreturnthenumber.

<echo><message>citrus:stringLength('HelloTestFramework')</message></echo>

Functionoutput:

20

translate()

Thisfunctionwillreplaceregularexpressionmatchingvaluesinsideastringrepresentationwithaspecifiedreplacementstring.

<echo><message>citrus:translate('H.lloTestFr.mework','\.','a')</message></echo>

Notethatthesecondparameterwillbearegularexpression.Thethirdparameterwillbeasimplereplacementstringvalue.

CitrusReferenceGuide

464Functions

Page 465: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Functionoutput:

HelloTestFramework

substringBefore()

Thefunctionwillsearchforthefirstoccurrenceofaspecifiedstringandwillreturnthesubstringbeforethatoccurrence.Letushaveacloserlookinasimpleexample:

<echo><message>citrus:substringBefore('Test/Framework','/')</message></echo>

Inthespecificexamplethefunctionwillsearchforthe‘/’characterandreturnthestringbeforethatindex.

Functionoutput:

Test

substringAfter()

Thefunctionwillsearchforthefirstoccurrenceofaspecifiedstringandwillreturnthesubstringafterthatoccurrence.Letusclarifythiswithasimpleexample:

<echo><message>citrus:substringAfter('Test/Framework','/')</message></echo>

SimilartothesubstringBeforefunctionthe‘/’characterisfoundinthestring.Butnowtheremainingstringisreturnedbythefunctionmeaningthesubstringafterthischaracterindex.

Functionoutput:

Framework

round()

CitrusReferenceGuide

465Functions

Page 466: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Thisisasimplemathematicfunctionthatwillrounddecimalnumbersrepresentationstotheirnearestnondecimalnumber.

<echo><message>citrus:round('3.14')</message></echo>

Functionoutput:

3

floor()

Thisfunctionwillrounddowndecimalnumbervalues.

<echo><message>citrus:floor('3.14')</message></echo>

Functionoutput:

3.0

ceiling()

Similartofloorfunction,butnowthefunctionwillroundupthedecimalnumbervalues.

<echo><message>citrus:ceiling('3.14')</message></echo>

Functionoutput:

4.0

randomNumber()

Therandomnumberfunctionwillprovideyoutheopportunitytogeneraterandomnumberstringscontainingpositivenumberletters.ThereisasingularBooleanparameterforthatfunctiondescribingwhetherthegeneratednumbershouldhaveexactlytheamountofdigits.Defaultvalueforthispaddingflagwillbetrue.

CitrusReferenceGuide

466Functions

Page 467: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Nextexamplewillshowthefunctionusage:

<variables><variablename="rndNumber1"value="citrus:randomNumber(10)"/><variablename="rndNumber2"value="citrus:randomNumber(10,true)"/><variablename="rndNumber2"value="citrus:randomNumber(10,false)"/><variablename="rndNumber3"value="citrus:randomNumber(3,false)"/></variables>

Functionoutput:

89546387655003485980638765065

randomString()

Thisfunctionwillgeneratearandomstringrepresentationwithadefinedlength.Asecondparameterforthisfunctionwilldefinethecaseofthegeneratedletters(UPPERCASE,LOWERCASE,MIXED).Thelastparameterallowsalsodigitcharactersinthegeneratedstring.Bydefaultdigitcharatersarenotallowed.

<variables><variablename="rndString0"value="$citrus:randomString(10)"/><variablename="rndString1"value="citrus:randomString(10)"/><variablename="rndString2"value="citrus:randomString(10,UPPERCASE)"/><variablename="rndString3"value="citrus:randomString(10,LOWERCASE)"/><variablename="rndString4"value="citrus:randomString(10,MIXED)"/><variablename="rndString4"value="citrus:randomString(10,MIXED,true)"/></variables>

Functionoutput:

HrGHOdfAerAgSSwedetGJSDFUTTRKUdtkhirtsuzVt567JkA32

randomEnumValue()

CitrusReferenceGuide

467Functions

Page 468: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Thisfunctionreturnsoneofitssuppliedarguments.Furthermoreyoucanspecifyacustomfunctionwithaconfiguredlistofvalues(theenumeration).Thefunctionwillrandomlyreturnanentrywhencalledwithoutarguments.Thispromotescodereuseandfacilitatesrefactoring.

InthenextsamplethefunctionisusedtosetahttpStatusCodevariabletooneofthegivenHTTPstatuscodes(200,401,500)

<variablename="httpStatusCode"value="citrus:randomEnumValue('200','401','500')"/>

Asmentionedbeforeyoucandefineacustomfunctionforyourveryspecificneedsinordertoeasilymanagealistofpredefinedvalueslikethis:

<citrus:function-libraryid="myCustomFunctionLibrary"prefix="custom:"><citrus-functionname="randomHttpStatusCode"ref="randomHttpStatusCodeFunction"/></citrus:function-library>

<beanid="randomHttpStatusCodeFunction"class="com.consol.citrus.functions.core.RandomEnumValueFunction"<propertyname="values"><list><value>200</value><value>500</value><value>401</value></list></property></bean>

Wehaveaddedacustomfunctionlibrarywithacustomfunctiondefinition.Thecustomfunction"randomHttpStatusCode"randomlychoosesanHTTPstatuscodeeachtimeitiscalled.Insidethetestyoucanusethefunctionlikethis:

<variablename="httpStatusCode"value="custom:randomHttpStatusCode()"/>

currentDate()

Thisfunctionwilldefinitelyhelpyouwhenaccessingthecurrentdate.Someexampleswillshowtheusageindetail:

<echo><message>citrus:currentDate()</message></echo><echo><message>citrus:currentDate('yyyy-MM-dd')</message></echo><echo><message>citrus:currentDate('yyyy-MM-ddHH:mm:ss')</message></echo>

CitrusReferenceGuide

468Functions

Page 469: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<echo><message>citrus:currentDate('yyyy-MM-dd'T'hh:mm:ss')</message></echo><echo><message>citrus:currentDate('yyyy-MM-ddHH:mm:ss','+1y')</message></echo><echo><message>citrus:currentDate('yyyy-MM-ddHH:mm:ss','+1M')</message></echo><echo><message>citrus:currentDate('yyyy-MM-ddHH:mm:ss','+1d')</message></echo><echo><message>citrus:currentDate('yyyy-MM-ddHH:mm:ss','+1h')</message></echo><echo><message>citrus:currentDate('yyyy-MM-ddHH:mm:ss','+1m')</message></echo><echo><message>citrus:currentDate('yyyy-MM-ddHH:mm:ss','+1s')</message></echo><echo><message>citrus:currentDate('yyyy-MM-ddHH:mm:ss','-1y')</message></echo>

NotethatthecurrentDatefunctionprovidestwoparameters.Firstparameterdescribesthedateformatstring.Thesecondwilldefineadateoffsetstringcontainingyear,month,days,hours,minutesorsecondsthatwillbeaddedorsubtractedtoorfromtheactualdatevalue.

Functionoutput:

01.09.20092009-09-012009-09-0112:00:002009-09-01T12:00:00

upperCase()

Thisfunctionconvertsanystringtouppercaseletters.

<echo><message>citrus:upperCase('HelloTestFramework')</message></echo>

Functionoutput:

HELLOTESTFRAMEWORK

lowerCase()

Thisfunctionconvertsanystringtolowercaseletters.

<echo><message>citrus:lowerCase('HelloTestFramework')</message></echo>

Functionoutput:

CitrusReferenceGuide

469Functions

Page 470: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

hellotestframework

average()

Thefunctionwillsumupallspecifiednumbervaluesanddividetheresultthroughthenumberofvalues.

<variablename="avg"value="citrus:average('3','4','5')"/>

avg=4.0

minimum()

Thisfunctionreturnstheminimumvalueinasetofnumbervalues.

<variablename="min"value="citrus:minimum('3','4','5')"/>

min=3.0

maximum()

Thisfunctionreturnsthemaximumvalueinasetofnumbervalues.

<variablename="max"value="citrus:maximum('3','4','5')"/>

max=5.0

sum()

Thefunctionwillsumupallnumbervalues.Thenumbervaluescanalsobenegative.

<variablename="sum"value="citrus:sum('3','4','5')"/>

sum=12.0

absolute()

Thefunctionwillreturntheabsolutenumbervalue.

CitrusReferenceGuide

470Functions

Page 471: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<variablename="abs"value="citrus:absolute('-3')"/>

abs=3.0

mapValue()

Thisfunctionimplementationmapsstringkeystostringvalues.Thisisveryhelpfulwhentheusedkeyisrandomlychosenatruntimeandthecorrespondingvalueisnotdefinedduringthedesigntime.

ThefollowingfunctionlibrarydefinesacustomfunctionformappingHTTPstatuscodestothecorrespondingmessages:

<citrus:function-libraryid="myCustomFunctionLibrary"prefix="custom:"><citrus-functionname="getHttpStatusMessage"ref="getHttpStatusMessageFunction"/></citrus:function-library>

<beanid="getHttpStatusMessageFunction"class="com.consol.citrus.functions.core.MapValueFunction"<propertyname="values"><map><entrykey="200"value="OK"/><entrykey="401"value="Unauthorized"/><entrykey="500"value="InternalServerError"/></map></property></bean>

InthisexamplethefunctionsetsthevariablehttpStatusMessagetothe'InternalServerError'stringdynamicallyatruntime.ThetestonlyknowstheHTTPstatuscodeanddoesnotcareaboutspellingandmessagelocales.

<variablename="httpStatusCodeMessage"value="custom:getHttpStatusMessage('500')"/>

randomUUID()

ThefunctionwillgeneratearandomJavaUUID.

<variablename="uuid"value="citrus:randomUUID()"/>

uuid=98fbd7b0-832e-4b85-b9d2-e0113ee88356

CitrusReferenceGuide

471Functions

Page 472: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

encodeBase64()

Thefunctionwillencodeastringtobinarydatausingbase64hexadecimalencoding.

<variablename="encoded"value="citrus:encodeBase64('HalloTestframework')"/>

encoded=VGVzdCBGcmFtZXdvcms=

decodeBase64()

Thefunctionwilldecodebinarydatatoacharactersequenceusingbase64hexadecimaldecoding.

<variablename="decoded"value="citrus:decodeBase64('VGVzdCBGcmFtZXdvcms=')"/>

decoded=HalloTestframework

escapeXml()

IfyouwanttodealwithescapedXMLinyourtestcaseyoumaywanttousethisfunction.ItautomaticallyescapesallXMLspecialcharacters.

<echo><message><![CDATA[citrus:escapeXml('<Message>HalloTestFramework</Message>')]]></message></echo>

<Message>HalloTestFramework</Message>

cdataSection()

UsuallyweuseCDATAsectionstodefinemessagepayloaddatainsideatestcase.WemightrunintoproblemswhenthepayloaditselfcontainsCDATAsectionsasnestedCDATAsectionsareprohibitedbyXMLnature.Inthiscasethenextfunctionshipsveryusefull.

CitrusReferenceGuide

472Functions

Page 473: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<variablename="cdata"value="citrus:cdataSection('payload')"/>

cdata=<![CDATA[payload]]>

digestAuthHeader()

Digestauthenticationisacommonlyusedsecurityalgorithm,especiallyinHttpcommunicationandSOAPWebServices.CitrusoffersafunctiontogenerateadigestauthenticationprincipleusedintheHttpheadersectionofamessage.

<variablename="digest"value="citrus:digestAuthHeader('username','password','authRealm','acegi','POST','http://127.0.0.1:8080','citrus','md5')"/>

Apossibledigestauthenticationheadervaluelookslikethis:

<Digestusername=foo,realm=arealm,nonce=MTMzNT,uri=http://127.0.0.1:8080,response=51f98c,opaque=b29a30,algorithm=md5>

YoucanusethesedigestheadersinmessagessentbyCitruslikethis:

<header><elementname="citrus_http_Authorization"value="vflig:digestAuthHeader('$username','$password','$authRealm','$nonceKey','POST','$uri','$opaque','$algorithm')"/></header>

ThiswillsetaHttpAuthorizationheaderwiththerespectivedigestintherequestmessage.Soyourtestisreadyforclientdigestauthentication.

localHostAddress()

Testcasesmayusethelocalhostaddressforsomereason(e.g.usedasauthenticationprinciple).Asthetestsmayrunondifferentmachinesatthesametimewecannotusestatichostaddresses.TheprovidedfunctionlocalHostAddress()readsthelocalhostnamedynamicallyatruntime.

<variablename="address"value="citrus:localHostAddress()"/>

CitrusReferenceGuide

473Functions

Page 474: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ApossiblevalueiseitherthehostnameasusedinDNSentryoranIPaddressvalue:

address=<192.168.2.100>

changeDate()

Thisfunctionworkswithdatevaluesandmanipulatesthoseatruntimebyaddingorremovingadatevalueoffset.Youcanmanipulateseveraldatefieldssuchas:year,month,day,hour,minuteorsecond.

Letusclarifythiswithasimpleexampleforthisfunction:

<echo><message>citrus:changeDate('01.01.2000','+1y+1M+1d')</message></echo><echo><message>citrus:changeDate(citrus:currentDate(),'-1M')</message></echo>

Functionoutput:

02.02.200113.04.2013

Asyoucanseethechangedatefunctionworksonstaticdatevaluesordynamicvariablevaluesorfunctionslikecitrus:currentDate().Bydefaultthechangedatefunctionrequiresadateformatsuchasthecurrentdatefunction('dd.MM.yyyy').Youcanalsodefineacustomdateformat:

<echo><message>citrus:changeDate('2000-01-10','-1M-1d','yyyy-MM-dd')</message></echo>

Functionoutput:

1999-12-09

Withthisyouareabletomanipulatealldatevaluesofstaticordynamicnatureattestruntime.

readFile()

CitrusReferenceGuide

474Functions

Page 475: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ThereadFilefunctionreadsafileresourcefromgivenfilepathandloadsthecompletefilecontentasfunctionresult.Thefilepathcanbeasystemfilepathaswellasaclasspathfileresource.Thefilepathcanhavetestvariablesaspartofthepathorfilename.Inadditiontothatthefilecontentcanalsohavetestvariablevaluesandotherfunctions.

Let'sseethisfunctioninaction:

<echo><message>citrus:readFile('classpath:some/path/to/file.txt')</message></echo><echo><message>citrus:readFile($filePath)</message></echo>

Thefunctionreadsthefilecontentandplacesthecontentatthepositionwherethefunctionhasbeencalled.ThismeansthatyoucanalsousethisfunctionaspartofStringsandmessagepayloadsforinstance.Thisisaverypowerfulwaytoextractlargemessagepartstoseparatefileresources.JustaddthereadFilefunctionsomewheretothemessagecontentandCitruswillloadtheextrafilecontentandplaceitrightintothemessagepayloadforyou.

message()

WhenmessagesareexchangedinCitrusthecontentisautomaticallysavedtoaninmemorystorageforfurtheraccessinthetestcase.Thatmeansthatfunctionsandtestactionscanaccessthemessagesthathavebeensentorreceivedwithinthetestcase.Themessagefunctionloadsamessagecontentfromthatmessagestore.Themessageisidentifiedbyitsname.Receiveandsendactionsusuallydefinethemessagename.Nowwecanloadthemessagepayloadwiththatname.

Let'sseethisfunctioninaction:

<echo><message>citrus:message(myRequest.payload())</message></echo>

ThefunctionaboveloadsthemessagenamedmyRequestfromthelocalmemorystore.Thisrequiresasendorreceiveactiontohavehandledthemessagebeforeinthesametestcase.

CitrusReferenceGuide

475Functions

Page 476: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

XMLDSL

<sendendpoint="someEndpoint"><messagename="myRequest"><payload>Somepayload</payload></message></send>

JavaDSL

send("someEndpoint").name("myRequest").payload("Somepayload");

Thenameofthemessageisimportant.Otherwisethemessagecannotbefoundinthelocalmessagestore.Note:amessagecaneitherbereceivedorsentwithanameinordertobestoredinthelocalmessagestore.Themessagefunctionisthenabletoaccessthemessagebyitsname.Inthefirstexamplethepayload()hasbeenloaded.Ofcoursewecanalsoaccessheaderinformation.

<echo><message>citrus:message(myRequest.header('Operation'))</message></echo>

ThesampleaboveloadstheheaderOperationofthemessage.

InJavaDSLthemessagestoreisalsoaccessibleovertheTestContext.

xpath()

ThexpathfunctionevaluatesaXpathexpressionsonsomeXMLsourceandreturnstheexpressionresultasString.

<echo><message><![CDATA[citrus:xpath('<message><id>1000</id></text>Sometextcontent</text></message>','/message/id')]]></echo>

TheXMLsourceisgivenasfirstfunctionparameterandcanbeloadedindifferentways.IntheexampleaboveastaticXMLsourcehasbeenused.WecouldloadtheXMLcontentfromexternalfileorjustuseatestvariable.

CitrusReferenceGuide

476Functions

Page 477: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<echo><message><![CDATA[citrus:xpath(citrus:readFile('some/path/to/file.xml'),'/message/id')]]></echo>

Alsoaccessingthelocalmessagestoreisvalidhere:

<echo><message><![CDATA[citrus:xpath(citrus:message(myRequest.payload()),'/message/id')]]></message</echo>

Thiscombinationisquitepowerfulasallpreviouslyexchangedmessagesinthetestareautomaticallystoredtothelocalmessagestore.Reusingdynamicmessagevaluesfromothermessagesbecomesveryeasythen.

jsonPath()

ThejsonPathfunctionevaluatesaJsonPathexpressionsonsomeJSONsourceandreturnstheexpressionresultasString.

<echo><message><![CDATA[citrus:jsonPath('"message":"id":1000,"text":"Sometextcontent"','$.message.id')]]></echo>

TheJSONsourceisgivenasfirstfunctionparameterandcanbeloadedindifferentways.IntheexampleaboveastaticJSONsourcehasbeenused.WecouldloadtheJSONcontentfromexternalfileorjustuseatestvariable.

<echo><message><![CDATA[citrus:jsonPath($jsonSource,'$.message.id')]]></message></echo>

Alsoaccessingthelocalmessagestoreisvalidhere:

<echo><message><![CDATA[citrus:jsonPath(citrus:message(myRequest.payload()),'$.message.id')]]></echo>

CitrusReferenceGuide

477Functions

Page 478: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Thiscombinationisquitepowerfulasallpreviouslyexchangedmessagesinthetestareautomaticallystoredtothelocalmessagestore.Reusingdynamicmessagevaluesfromothermessagesbecomesveryeasythen.

CitrusReferenceGuide

478Functions

Page 479: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ValidationmatcherMessagevalidationinCitrusisessential.Theframeworkoffersseveralvalidationmechanismsfordifferentmessagetypesandformats.Withtestvariablesweareabletocheckforsimplevalueequality.Weensurethatmessageentriesareequaltopredefinedexpectedvalues.Validationmatcheraddpowerfulassertionfunctionalityontopofthat.YoujustcanusethepredefinedvalidationmatcherfunctionalitiesinordertoperformmorecomplexassertionslikecontainsorisNumberinyourvalidationstatements.

ThefollowingsectionsdescribetheCitrusdefaultvalidationmatcherimplementationsthatarereadyforusage.Thematcherimplementationsshouldcoverthebasicassertionsoncharactersequencesandnumbers.Ofcourseyoucanaddcustomvalidationmatcherimplementationsinordertomeetyourveryspecificvalidationassertions,too.

Firstofallletushavealookatavalidationmatcherstatementinactionsoweunderstandhowtousetheminatestcase.

<message><payload><RequestMessage><MessageBody><Customer><Id>@greaterThan(0)@</Id><Name>@equalsIgnoreCase('foo')@</Name></Customer></MessageBody></RequestMessage></payload></message>

Thelistingabovedescribesanormalmessagevalidationblockinsideareceivetestaction.WeusesomeinlinemessagepayloadtemplateasCDATA.AsyouknowCitruswillcomparetheactualmessagepayloadtothisexpectedtemplateinDOMtreecomparison.Inadditiontothatyoucansimplyincludevalidationmatcherstatements.ThemessageelementIdisautomaticallyvalidatedtobeanumbergreaterthanzeroandtheNamecharactersequenceissupposedtomatch'foo'ignoringcasespellingconsiderations.

CitrusReferenceGuide

479ValidationMatchers

Page 480: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Pleasenotethespecialvalidationmatchersyntax.Thestatementsaresurroundedwith'@'markersandareidentifiedbysomeuniquename.Theoptionalparameterspassedtothematcherimplementationstatetheexpectedvaluestomatch.

TipYoucanusevalidationmatcherwithallvalidationmechanisms-notonlywithXMLvalidation.Plaintext,JSON,SQLresultsetvalidationarealsosupported.

Asetofvalidationmatcherimplementationsisusuallycombinedtoavalidationmatcherlibrary.Thelibraryhasaprefixthatwillidentifythevalidationmatcherinsidethetestcase.Thedefaulttestframeworkvalidationmatcherlibraryusesadefaultprefix(citrus).Youcanwriteyourownvalidationmatcherlibraryusingyourownprefixinordertoextendthetestframeworkfunctionalitywheneveryouwant.

ThelibraryisbuiltintheSpringconfigurationandcontainsasetofvalidationmatcherthatareofpublicuse.

<citrus:validationmatcher-libraryid="testMatcherLibrary"prefix="foo:"><citrus:matchername="isNumber">class="com.consol.citrus.validation.matcher.core.IsNumberValidationMatcher"/><citrus:matchername="contains">class="com.consol.citrus.validation.matcher.core.ContainsValidationMatcher"/><citrus:matchername="customMatcher">ref="customMatcherBean"/>...</citrus:validationmatcher-library>

AsyoucanseethelibrarydefinesonetomanyvalidationmatchermemberseitherreferencedasnormalSpringbeanorbyitsimplementingJavaclassname.Citrusconstructsthelibraryandyouareabletousethevalidationmatcherinyourtestcasewiththeleadinglibraryprefixjustlikethis:

@foo:isNumber()@@foo:contains()@@foo:customMatcher()@

TipYoucanaddcustomvalidationmatcherimplementationsandcustomvalidationmatcherlibraries.Justuseacustomprefixforyourlibrary.ThedefaultCitrusvalidationmatcherlibraryusesnoprefix.SeenowthefollowingsectionsdescribingthedefaultvalidationvalidationmatcherinCitrus.

ignore()

CitrusReferenceGuide

480ValidationMatchers

Page 481: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Theignorevalidationmatcherisaspecialmatcherthatignoresthevalueandisalwayspositiveinitsoutcome.Youshouldusetheignorevalidationmatcherwhenonlyvalidatingthepureexistenceofanelement.Thevalueisignoredbuttheelementhastobepresentinthemessagepayload.

<message><payload><RequestMessage><MessageBody><Customer><Id>@ignore()@</Id><Name>@equalsIgnoreCase('foo')@</Name></Customer></MessageBody></RequestMessage></payload></message>

Note

Theignorevalidationmatcheristheonlyvalidationmatcherthatisabletoskipthefunctionparameterbody.Soyoucanuseboth@ignore()@and@ignore@.

matchesXml()

TheXMLvalidationmatcherimplementationisthepossiblymostexcitingone,aswecanvalidatenestedXMLwithfullvalidationpower(e.g.ignoringelements,variablesupport).ThematcherchecksanestedXMLfragmenttocompareagainstexpectedXML.ForinstancewereceivefollowingXMLmessagepayloadforvalidation:

<GetCustomerMessage><CustomerDetails><Id>5</Id><Name>Christoph</Name><Configuration><![CDATA[<config><premium>true</premium><last-login>2012-02-24T23:34:23</last-login><link>http://www.citrusframework.org/customer/5</link></config>]]></Configuration></CustomerDetails></GetCustomerMessage>

CitrusReferenceGuide

481ValidationMatchers

Page 482: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

AsyoucanseethemessagepayloadcontainssomeconfigurationasnestedXMLdatainaCDATAsection.WecouldvalidatethisCDATAsectionasstaticcharactersequencecomparison,true.Butthetimestampchangesitsvaluecontinuously.ThisbreaksthestaticvalidationforCDATAelementsinXML.FortunatelythenewXMLvalidationmatcherprovidesasolutionforus:

<message><payload><GetCustomerMessage><CustomerDetails><Id>5</Id><Name>Christoph</Name><Configuration>citrus:cdataSection('@matchesXml('<config><premium>$isPremium</premium><last-login>@ignore@</last-login><link>http://www.citrusframework.org/customer/5</link></config>')@')</Configuration></CustomerDetails></GetCustomerMessage></payload></message>

WiththevalidationmatcheryouareabletovalidatethenestedXMLwithfullvalidationpower.IgnoringelementsispossibleandwecanalsousevariablesinourcontrolXML.

NoteNestedCDATAelementswithinotherCDATAsectionsarenotallowedbyXMLstandard.ThisiswhywecreatethenestedCDATAsectionontheflywiththefunctioncdataSection().###equalsIgnoreCase()

Thismatcherimplementationchecksforequalitywithoutanycasespellingconsiderations.Thematcherexpectsasingleparameterastheexpectedcharactersequencetocheckfor.

<value>@equalsIgnoreCase('foo')@</value>

contains()

Thismatchersearchesforacharactersequenceinsidetheactualvalue.Ifthecharactersequenceisnotfoundsomewherethematcherstartscomplaining.

<value>@contains('foo')@</value>

CitrusReferenceGuide

482ValidationMatchers

Page 483: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Thevalidationmatcheralsoexistinacaseinsensitivevariant.

<value>@containsIgnoreCase('foo')@</value>

startsWith()

Thematcherimplementationassertsthatthegivenvaluestartswithacharactersequenceotherwisethematcherwillarisesomeerror.

<value>@startsWith('foo')@</value>

endsWith()

Endswithmatchervalidatesavaluetoendwithagivencharactersequence.

<value>@endsWith('foo')@</value>

matches()

Youcancheckavaluetomeetaregularexpressionwiththisvalidationmatcher.Thisisforinstanceveryusefulforemailaddressvalidation.

<value>@matches('[a-z0-9]')@</value>

matchesDatePattern()

Datevaluesarealwaysdifficulttocheckforequality.Especiallywhenyouhavemillisecondtimestampstodealwith.Thereforethedatepatternvalidationmatchershouldhavesomeimprovementforyou.Yousimplyvalidatethedateformatpatterninsteadofcheckingfortotalequality.

<value>@matchesDatePattern('yyyy-MM-dd')@</value>

Theexamplelistingusesadateformatpatternthatisexpected.Theactualdatevalueisparsedaccordingtothispatternandmaycauseerrorsincasethevalueisnovaliddatematchingthedesiredformat.

CitrusReferenceGuide

483ValidationMatchers

Page 484: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

isNumber()

Checkingonvaluestobeofnumericnatureisessential.Theactualvaluemustbeanumericnumberotherwisethematcherraiseserrors.Thematcherimplementationdoesnotevaluateanyparameters.

<value>@isNumber()@</value>

lowerThan()

Thismatcherchecksanumbertobelowerthanagiventhresholdvalue.

<value>@lowerThan(5)@</value>

greaterThan()

Thematcherimplementationwillcheckonnumericvaluestobegreaterthanaminimumvalue.

<value>@greaterThan(5)@</value>

isWeekday()

Thematcherworksondatevaluesandchecksthatagivendateevaluatestotheexpecteddayoftheweek.Theuserdefinestheexpecteddaybyitsnameinuppercasecharacters.Thematcherfailsincasethegivendateisanotherweekdaythanexpected.

<someDate>@isWeekday('MONDAY')@</someDate>

Possiblevaluesfortheexpecteddayoftheweekare:MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAYorSUNDAY.

Thefieldvaluehastobeadatevalueotherwisethematcherwillfailtoparsethedate.Thematcherrequiresadateformatwhichisdd.MM.yyyybydefault.Youcanchangethisdateformatasfollows:

<someDate>@isWeekday(MONDAY('yyyy-MM-dd'))@</someDate>

CitrusReferenceGuide

484ValidationMatchers

Page 485: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Nowthematcherusesthecustomdateformatinordertoparsethedatevalueforevaluation.Thevalidationmatcheralsoworkswithdatetimevalues.Inthiscaseyouhavetogiveavaliddatetimeformatrespectively(e.g.FRIDAY('yyyy-MM-dd'T'hh:mm:ss')).

variable()

Thisisaveryspecialvalidationmatcher.Insteadofperformingavalidationlogicyoucansavetheactualvaluepassedtothevalidationmatcherasnewtestvariable.Thiscomesveryhandyasyoucanusethematcherwhereveryouwant:JSONmessagepayloads,XMLmessagepayloads,headersandsoon.

<value>@variable('foo')@</value>

Thevalidationmatchercreatesanewvariablefoowiththeactualelementvalueasvariablevalue.Whenleavingoutthecontrolvaluethefieldnameitselfisusedasvariablename.

<date>@variable()@</date>

Thiscreatesanewvariabledatewiththeactualelementvalueasvariablevalue.

dateRange()

Thematcherworksondatevaluesandchecksthatagivendateiswithintheexpecteddaterange.Theuserdefinestheexpecteddaterangebyspecifyingafrom-date,ato-dateandoptionallyadateformat.Thematcherfailswhenthegivendateliesoutsidetheexpecteddaterange.

<someDate>@dateRange('01-12-2015','31-12-2015','dd-MM-yyyy')@</someDate>

Possiblevalidvalueswouldbe'somedate'>='01-12-2015'and'somedate'<='31-12-2015'

Thedate-formatisoptionalandwhenomitteditisassumedthatalldatesmatchthedefaultdateformatyyyy-MM-dd.Whenspecifyingacustomdateformatusejava'sdateformatasareferenceforvaliddateformats.Onlydateswereusedintheexampleabovebutwecouldjustaseasilyuseddateandtimeasshownintheexamplebelow

CitrusReferenceGuide

485ValidationMatchers

Page 486: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<someDate>@dateRange('2015.12.0107:00:00','2015.12.0119:00:00','yyyy.MM.ddHH:mm:ss')@</someDate

assertThat()

Hamcrestisaverypowerfulmatcherlibrarywithextraordinarymatcherimplementations.YoucanuseHamcrestmatchersalsoasCitrusvalidationmatcher.

<someValue>@assertThat(equalTo(foo))@</someValue>

InthelistingaboveweareusingtheequalTo()matcher.AllHamcrestmatchersaresurroundedbyaassertThatexpression.YouareabletocombineseveralHamcrestmatcherstheninordertoconstructverypowerfulvalidationlogic.Seethefollowingexamplesonwhatispossiblethen:

<someValue>@assertThat(equalTo(value))@</someValue><someValue>@assertThat(not(equalTo(other))@</someValue><someValue>@assertThat(is(not(other)))@</someValue><someValue>@assertThat(not(is(other)))@</someValue><someValue>@assertThat(equalToIgnoringCase(VALUE))@</someValue><someValue>@assertThat(containsString(lue))@</someValue><someValue>@assertThat(not(containsString(other)))@</someValue><someValue>@assertThat(startsWith(val))@</someValue><someValue>@assertThat(endsWith(lue))@</someValue><someValue>@assertThat(anyOf(startsWith(val),endsWith(lue)))@</someValue><someValue>@assertThat(allOf(startsWith(val),endsWith(lue)))@</someValue><someValue>@assertThat(isEmptyString())@</someValue><someValue>@assertThat(not(isEmptyString()))@</someValue><someValue>@assertThat(isEmptyOrNullString())@</someValue><someValue>@assertThat(nullValue())@</someValue><someValue>@assertThat(notNullValue())@</someValue><someValue>@assertThat(empty())@</someValue><someValue>@assertThat(not(empty())@</someValue><someValue>@assertThat(greaterThan(4))@</someValue><someValue>@assertThat(allOf(greaterThan(4),lessThan(6),not(lessThan(5)))@</someValue><someValue>@assertThat(is(not(greaterThan(5))))@</someValue><someValue>@assertThat(greaterThanOrEqualTo(5))@</someValue><someValue>@assertThat(lessThan(5))@</someValue><someValue>@assertThat(not(lessThan(1)))@</someValue><someValue>@assertThat(lessThanOrEqualTo(4))@</someValue><someValue>@assertThat(hasSize(5))@</someValue>

Citruswillautomaticallyperformvalidationmatchersontheelementvalue.Onlyifallmatchersaresatisfiedthevalidationwillpass.

CitrusReferenceGuide

486ValidationMatchers

Page 487: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

CitrusReferenceGuide

487ValidationMatchers

Page 488: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

DatadictionariesDatadictionariesinCitrusprovideanewwaytomanipulatemessagepayloaddatabeforeamessageissentorreceived.Thedictionarydefinesasetofkeysandrespectivevalues.Justlikeeveryotherdictionaryitisusedtotranslatethings.Inourcasewetranslatemessagedataelements.

Youcantranslatecommonmessageelementsthatareusedwidelythroughoutyourdomainmodel.AsCitrusdealswithdifferenttypesofmessagedata(e.g.XML,JSON)wehavedifferentdictionaryimplementationsthataredescribedinthenextsections.

XMLdatadictionaries

XMLdatadictionariesdoapplytoXMLmessageformatpayloads,ofcourse.IngeneralweaddadictionarytothebasicCitrusSpringapplicationcontextinordertomakethedictionaryvisibletoalltestcases:

<citrus:xml-data-dictionaryid="nodeMappingDataDictionary"><citrus:mappings><citrus:mappingpath="TestMessage.MessageId"value="$messageId"/><citrus:mappingpath="TestMessage.CorrelationId"value="$correlationId"/><citrus:mappingpath="TestMessage.User"value="Christoph"/><citrus:mappingpath="TestMessage.TimeStamp"value="citrus:currentDate()"/></citrus:mappings></citrus:xml-data-dictionary>

AsyoucanseethedictionaryisnothingbutanormalSpringbeandefinition.TheNodeMappingDataDictionaryimplementationreceivesamapofkeyvaluepairswherethekeyisamessageelementpathexpression.ForXMLpayloadsthemessageelementtreeistraversedsothepathexpressionisbuiltforanexactmessageelementinsidethepayload.Ifmatchedtherespectivevalueissetaccordinglythroughthedictionary.

Besidesdefiningthedictionarykeyvaluemappingsaspropertymapinsidethebeandefinitionwecanextractthemappingdatatoanexternalfile.

<citrus:xml-data-dictionaryid="nodeMappingDataDictionary"><citrus:mapping-filepath="classpath:com/consol/citrus/sample.dictionary"/></citrus:xml-data-dictionary>

ThemappingfilecontentjustlookslikeanormalpropertyfileinJava:

CitrusReferenceGuide

488Datadictionary

Page 489: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TestMessage.MessageId=$messageIdTestMessage.CorrelationId=$correlationIdTestMessage.User=ChristophTestMessage.TimeStamp=citrus:currentDate()

YoucansetanymessageelementvalueinsidetheXMLmessagepayload.ThepathexpressionalsosupportsXMLattributes.Justusetheattributenameaslastpartofthepathexpression.LetushaveacloserlookatasampleXMLmessagepayloadwithattributes:

<TestMessage><Username="Christoph"age="18"/></TestMessage>

WiththissampleXMLpayloadgivenwecanaccesstheattributesinthedatadictionaryasfollows:

<citrus:mappingpath="TestMessage.User.name"value="$userName"/><citrus:mappingpath="TestMessage.User.age"value="$userAge"/>

TheNodeMappingDataDictionaryimplementationiseasytouseandfitsthebasicneedsforXMLdatadictionaries.Themessageelementpathexpressionsareverysimpleanddofitbasicneeds.HoweverwhenmorecomplexXMLpayloadsapplyfortranslationwemightreachtheboundarieshere.

FormorecomplexXMLmessagepayloadsXPathdatadictionariesareveryeffective:

<citrus:xpath-data-dictionaryid="xpathMappingDataDictionary"><citrus:mappings><citrus:mappingpath="//TestMessage/MessageId"value="$messageId"/><citrus:mappingpath="//TestMessage/CorrelationId"value="$correlationId"/><citrus:mappingpath="//TestMessage/User"value="Christoph"/><citrus:mappingpath="//TestMessage/User/@id"value="123"/><citrus:mappingpath="//TestMessage/TimeStamp"value="citrus:currentDate()"/></citrus:mappings></citrus:xpath-data-dictionary>

AsexpectedXPathmappingexpressionsarewaymorepowerfulandcanalsohandleverycomplexscenarioswithXMLnamespaces,attributesandnodelists.JustlikethenodemappingdictionarytheXPathmappingdictionarydoesalsosupportvariables,functionsandanexternalmappingfile.

CitrusReferenceGuide

489Datadictionary

Page 490: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

XPathworksfinewithnamespaces.IngeneralitisgoodpracticetodefineanamespacecontextwhereyoumapnamespaceURIvalueswithprefixvalues.SoyourXPathexpressionisalwaysexactandevaluationisstrict.InCitrustheNamespaceContextBuilderwhichisalsoaddedasnormalSpringbeantotheapplicationcontextmanagesnamespacesusedinyourXPathexpressions.SeeourXMLandXPAthchaptersinthisdocumentationfordetaileddescriptionhowtoaccomplishfailsafeXPathexpressionswithnamespaces.

ThiscompletestheXMLdatadictionaryusageinCitrus.Lateronwewillseesomemoreadvanceddatadictionaryscenarioswherewewilldiscusstheusageofdictionaryscopesandmappingstrategies.ButbeforethatletushavealookatothermessageformatslikeJSONmessages.

JSONdatadictionaries

JSONdatadictionariescomplementwithXMLdatadictionaries.AsusualwehavetoaddtheJSONdatadictionarytothebasicSpringapplicationcontextfirst.OncethisisdonethedatadictionaryautomaticallyappliesforallJSONmessagepayloadsinCitrus.ThismeansthatallJSONmessagessentandreceivedgettranslatedwiththeJSONdatadictionaryimplementation.

Citrususesmessagetypesinordertoevaluatewhichdatadictionarymayfittothemessagethatiscurrentlyprocessed.Asusualyoucandefinethemessagetypedirectlyinyourtestcaseasattributeinsidethesendingandreceivingmessageaction.

LetusseeasimpledictionaryforJSONdata:

<citrus:json-data-dictionaryid="jsonMappingDataDictionary"><citrus:mappings><citrus:mappingpath="TestMessage.MessageId"value="$messageId"/><citrus:mappingpath="TestMessage.CorrelationId"value="$correlationId"/><citrus:mappingpath="TestMessage.User"value="Christoph"/><citrus:mappingpath="TestMessage.TimeStamp"value="citrus:currentDate()"/></citrus:mappings></citrus:json-data-dictionary>

ThemessagepathexpressionsdolookverysimilartothoseusedinXMLdatadictionaries.HerethepathexpressionkeysdoapplytotheJSONobjectgraph.SeethefollowingsampleJSONdatawhichperfectlyappliestothedictionaryexpressionsabove.

"TestMessage":"MessageId":"1122334455",

CitrusReferenceGuide

490Datadictionary

Page 491: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

"CorrelationId":"100000001","User":"Christoph","TimeStamp":1234567890

ThepathexpressionswillmatchaveryspecificmessageelementinsidetheJSONobjectgraph.Thedictionarywillautomaticallysetthemessageelementvaluesthen.ThepathexpressionsareeasytouseasyoucantraversetheJSONobjectgraphveryeasy.

Ofcoursethedatadictionarydoesalsosupporttestvariables,functions.AlsoveryinterestingistheusageofJSONarrays.AJSONarrayelementisreferencedinadatadictionarylikethis:

<citrus:mappingpath="TestMessage.Users[0]"value="Christoph"/><citrus:mappingpath="TestMessage.Users[1]"value="Julia"/>

TheUserselementisaJSONarray,sowecanaccesstheelementswithindex.NestingJSONobjectsandarraysisalsosupportedsoyoucanalsohandlemorecomplexJSONdata.

TheJsonMappingDataDictionaryimplementationiseasytouseandfitsthebasicneedsforJSONdatadictionaries.Themessageelementpathexpressionsareverysimpleanddofitbasicneeds.HoweverwhenmorecomplexJSONpayloadsapplyfortranslationwemightreachtheboundarieshere.

FormorecomplexJSONmessagepayloadsJsonPathdatadictionariesareveryeffective:

<citrus:json-path-data-dictionaryid="jsonMappingDataDictionary"><citrus:mappings><citrus:mappingpath="$.TestMessage.MessageId"value="$messageId"/><citrus:mappingpath="$..CorrelationId"value="$correlationId"/><citrus:mappingpath="$..Users[0]"value="Christoph"/><citrus:mappingpath="$.TestMessage.TimeStamp"value="citrus:currentDate()"/></citrus:mappings></citrus:json-path-data-dictionary>

JsonPathmappingexpressionsarewaymorepowerfulandcanalsohandleverycomplexscenarios.YoucanapplyforallelementsnamedCorrelationIdinonesingleentryforinstance.

Dictionaryscopes

CitrusReferenceGuide

491Datadictionary

Page 492: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

NowthatwehavelearnedhowtoadddatadictionariestoCitrusweneedtodiscusssomeadvancedtopics.Datadictionaryscopesdodefinetheboundarieswherethedictionarymayapply.Bydefaultdatadictionariesareglobalscopedictionaries.ThismeansthatthedatadictionaryappliestoallmessagessentandreceivedwithCitrus.OfcoursemessagetypesareconsideredsoXMLdatadictionariesdoonlyapplytoXMLmessagetypes.Howeverglobalscopedictionarieswillbeactivatedthroughoutalltestcasesandactions.

Youcanoverwritethedictionaryscope.Forinstanceinordertouseanexplicitscope.Whenthisisdonethedictionarywilnotapplyautomaticallybuttheuserhastoexplicitlysetthedatadictionaryinsendingorreceivingtestaction.Thiswayyoucanactivatethedictionarytoaveryspecialsetoftestactions.

<citrus:xml-data-dictionaryid="specialDataDictionary"global-scope="false"><citrus:mapping-filepath="classpath:com/consol/citrus/sample.dictionary"/></citrus:xml-data-dictionary>

Wesettheglobalscopepropertytofalsesothedictionaryishandledinexplicitscope.Thismeansthatyouhavetosetthedatadictionaryexplicitlyinyourtestactions:

XMLDSL

<sendendpoint="myEndpoint"><messagedata-dictionary="specialDataDictionary"><payload><TestMessage>HelloCitrus"/TestMessage></payload></message></send>

JavaDSLdesignerandrunner

@CitrusTestpublicvoiddictionaryTest()send(myEndpoint).payload("<TestMessage>HelloCitrus"/TestMessage>").dictionary("specialDataDictionary");

Thesampleaboveisasendingtestactionwithanexplicitdatadictionaryreferenceset.Beforesendingthemessagethedictionaryisaskedfortranslation.Soallmatchingmessageelementvalueswillbesetbythedictionaryaccordingly.Otherglobaldata

CitrusReferenceGuide

492Datadictionary

Page 493: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

dictionariesdoalsoapplyforthismessagebuttheexplicitdictionarywillalwaysoverwritethemessageelementvalues.

Pathmappingstrategies

Anotheradvancedtopicaboutdatadictionariesisthepathmappingstrategy.WhenusingsimplepathexpressionsthedefaultstrategyisalwaysEXACT.Thismeansthatthepathexpressionhastoevaluateexactlytoamessageelementwithinthepayloaddata.Andonlythisexactmessageelementistranslated.

Youcansetyourownpathmappingstrategyinordertochangethisbehavior.ForinstanceanothermappingstrategywouldbeSTARS_WITH.Allelementsaretranslatedthatstartwithacertainpathexpression.Letusclarifythiswithanexample:

<citrus:xml-data-dictionaryid="nodeMappingDataDictionary"mapping-strategy="STARTS_WITH"><citrus:mappings><citrus:mappingpath="TestMessage.Property"value="citrus:randomString()"/></citrus:mappings></citrus:xml-data-dictionary>

NowwiththepathmappingstrategysettoSTARS_WITHallmessageelementpathexpressionsstartingwithTestMessage.Propertywillfindtranslationinthisdictionary.Followingsamplemessagepayloadwouldbetranslatedaccordingly:

<TestMessage><Property>XXX</Property><PropertyName>XXX</PropertyName><PropertyValue>XXX</PropertyValue></TestMessage>

AllchildelementsofTestMessagestartingwithPropertywillbetranslatedwiththisdatadictionary.IntheresultingmessagepayloadCitruswillusearandomstringasvaluefortheseelementsasweusedthecitrus:randomString()functioninthedictionarymapping.

ThenextmappingstrategywouldbeENDS_WITH.Nosurpriseshere-thismappingstrategylooksformessageelementsthatendwithacertainpathexpression.Againasimpleexamplewillclarifythisforyou.

<citrus:xml-data-dictionaryid="nodeMappingDataDictionary"mapping-strategy="ENDS_WITH"><citrus:mappings><citrus:mappingpath="Id"value="citrus:randomNumber()"/>

CitrusReferenceGuide

493Datadictionary

Page 494: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

</citrus:mappings></citrus:xml-data-dictionary>

Againletusseesomesamplemessagepayloadforthisdictionaryusage:

<TestMessage><RequestId>XXX</RequestId><Properties><Property><PropertyId>XXX</PropertyId><PropertyValue>XXX</PropertyValue></Property><Property><PropertyId>XXX</PropertyId><PropertyValue>XXX</PropertyValue></Property></Properties></TestMessage>

InthissampleallmessageelementsendingwithIdwouldbetranslatedwitharandomnumber.Nomatterwhereinthemessagetreetheelementsarelocated.Thisisquiteusefulbutalsoverypowerful.Sobecarefultousethisstrategyinglobaldatadictionariesasitmaytranslatemessageelementsthatyouwouldnotexpectinthefirstplace.

CitrusReferenceGuide

494Datadictionary

Page 495: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TestactorsTheconceptoftestactorscametoourmindwhenreusingCitrustestcasesinend-to-endtestscenarios.UsuallyCitrussimulatesallinterfacepartnerswithinatestcasewhichisgreatforcontinuousintegrationtesting.Inend-to-endintegrationtestscenariossomeofourinterfacepartnersmayberealandalive.SomeotherinterfacepartnersstillrequireCitrussimulationlogic.

ItwouldbegreatifwecouldreusetheCitrusintegrationtestsinthistestsetupaswehavethecompletetestflowofmessagesavailableintheCitrustests.Weonlyhavetoremovethesimulatedsend/receiveactionsforthoserealinterfacepartnerapplicationswhichareavailableinourend-to-endtestsetup.

Withtestactorswehavetheopportunitytolinktestactions,inparticularsend/receivemessageactions,toatestactor.Thetestactorcanbedisabledinconfigurationveryeasyandfollowingfromthatalllinkedsend/receiveactionsaredisabled,too.OneCitrustestcaseisrunnablewithdifferenttestsetupscenarioswheredifferentpartnerapplicationsontheonehandareavailableasreallifeapplicationsandontheotherhandmyrequiresimulation.

Definetestactors

FirstthingtodoistodefineoneormoretestactorsinCitrusconfiguration.Atestactorrepresentsaparticipatingparty(e.g.interfacepartner,backendapplication).WewritethetestactorsintothecentralSpringapplicationcontext.WecanuseaspecialCitrusSpringXMLschemasodefinitionsarequiteeasy:

<citrus:actorid="travelagency"name="TRAVEL_AGENCY"/><citrus:actorid="royalairline"name="ROYAL_AIRLINE"/><citrus:actorid="smartariline"name="SMART_AIRLINE"/>

Thelistingabovedefinesthreetestactorsparticipatinginourtestscenario.AtravelagencyapplicationwhichissimulatedbyCitrusasacallingclient,thesmartairlineapplicationandaroyalairlineapplication.Nowwehavethetestactorsdefinedwecanlinkthosetomessagesender/receiverinstancesand/ortestactionswithinourtestcase.

Linktestactors

CitrusReferenceGuide

495Testactors

Page 496: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Weneedtolinkthetestactorstomessagesendandreceiveactionsinourtestcases.Wecandothisintwodifferentways.Firstwecansetatestactorreferenceonamessagesenderandmessagereceiver.

<citrus-jms:sync-endpointid="royalAirlineBookingEndpoint"destination-name="$royal.airline.request.queue"actor="royalairline"/>

Nowalltestactionsthatareusingthesemessagereceiverandmessagesenderinstancesarelinkedtothetestactor.Inadditiontothatyoucanalsoexplicitlylinktestactionstotestactorsinatest.

<receiveendpoint="royalAirlineBookingEndpoint"actor="royalairline"><message>[...]</message></receive>

<sendendpoint="royalAirlineBookingEndpoint"actor="royalairline"><message>[...]</message></send>

Thisexplicitlylinkstestactorstotestactionssoyoucandecidewhichlinkshouldbesetwithouthavingtorelyonthemessagereceiverandsenderconfiguration.

Disabletestactors

Usuallybothairlineapplicationsaresimulatedinourintegrationtests.Butthistimewewanttochangethisbyintroducingaroyalairlineapplicationwhichisonlineasarealapplicationinstance.SoweneedtoskipallsimulatedmessageinteractionsfortheroyalairlineapplicationinourCitrustests.Thisiseasyaswehavelinkedallsend/receiveactionstooneofourtestactors.Sowencandisabletheroyalairlinetestactorinourconfiguration:

<citrus:actorid="royalairline"name="ROYAL_AIRLINE"disabled="true"/>

Anytestactionlinkedtothistestactorisnowskipped.Asweintroducedarealroyalairlineapplicationinourtestscenariotherequestsgetansweredandthetestshouldbesuccessfulwithinthisend-to-endtestscenario.Thetravelagencyandthesmartairline

CitrusReferenceGuide

496Testactors

Page 497: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

stillgetsimulatedbyCitrus.ThisisaperfectwayofreusingintegrationtestsindifferenttestscenarioswhereyouenableanddisablesimulatedparticipatingpartiesinCitrus.

ImportantServerportsmaybeofspecialinterestwhendealingwithdifferenttestscenarios.YoumayhavetoalsodisableaCitrusembeddedJettyserverinstanceinordertoavoidportbindingconflictsandyoumayhavetowireendpointURIsaccordinglybeforeexecutingatest.ThereallifeapplicationmaynotusethesameportandipastheCitrusembeddedserversforsimulation.

CitrusReferenceGuide

497Testactors

Page 498: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TestsuiteactionsAtestframeworkshouldalsoprovidethefunctionalitytodosomeworkbeforeandafterthetestrun.Youcouldthinkofpreparing/deletingthedatainadatabaseorstarting/stoppingaserverinthissectionbefore/afteratestrun.ThesetasksfitbestintotheinitializationandcleanupphasesofCitrus.

NoteItisimportanttonoticethattheCitrusconfigurationcomponentsthatwearegoingtouseinthenextsectionbelongtoaseparateXMLnamespacecitrus-test.WehavetoaddthenamespacedeclarationtotheXMLrootelementofourXMLconfigurationfileaccordingly.

<spring:beansxmlns="http://www.citrusframework.org/schema/testcase"xmlns:spring="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:citrus-test="http://www.citrusframework.org/schema/testcase"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/testcasehttp://www.citrusframework.org/schema/testcase/citrus-testcase.xsd">

[...]

</beans>

Beforesuite

Youcaninfluencethebehaviorofatestrunintheinitializationphaseactuallybeforethetestsareexecuted.Seethenextcodeexampletofindouthowitworkswithactionsthattakeplacebeforethefirsttestisexecuted:

XMLConfig

<citrus:before-suiteid="actionsBeforeSuite"><citrus:actions><!--listofactionsbeforesuite--></citrus:actions></citrus:before-suite>

CitrusReferenceGuide

498Testsuite

Page 499: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TheCitrusconfigurationcomponentholdsalistofCitrustestactionsthatgetexecutedbeforethetestsuiterun.YoucanaddallCitrustestactionshereasyouwoulddoinanormaltestcasedefinition.

XMLConfig

<citrus:before-suiteid="actionsBeforeSuite"><citrus:actions><citrus-test:sqldataSource="testDataSource"/><citrus-test:statement>CREATETABLEPERSON(IDinteger,NAMEchar(250))</citrus-test:statement</citrus-test:sql></citrus:actions></citrus:before-suite>

NotethatwemustusetheCitrustestcasenamespaceforthenestedtestactiondefinitions.WeaccessthedatabaseandcreateatablePERSONwhichisobviouslyneededinourtestcases.Youcanthinkofseveralactionsheretopreparethedatabaseforinstance.

TipCitrusoffersspecialstartupandshutdownactionsthatmaystartandstopserverimplementationsautomatically.ThismightbehelpfulwhendealingwithHttpserversorWebServicecontainerslikeJetty.Youcanalsothinkofstarting/stoppingaJMSbrokerbeforeatestrun.

SofarwehaveusedXMLDSLactionsinbeforesuiteconfiguration.NowifyouexclusivelywanttouseJavaDSLyoucandothesamewithaddingacustomclassthatextendsTestDesignerBeforeSuiteSupportorTestRunnerBeforeSuiteSupport.

JavaDSLdesigner

publicclassMyBeforeSuiteextendsTestDesignerBeforeSuiteSupport@OverridepublicvoidbeforeSuite(TestDesignerdesigner)designer.echo("Thisactionshouldbeexecutedbeforesuite");

ThecustomimplementationextendsTestDesignerBeforeSuiteSupportandthereforehastoimplementthemethodbeforeSuite.ThismethodaddsomeJavaDSLdesignerlogictothebeforesuite.Thedesignerinstanceisinjectedasmethodargument.Youcan

CitrusReferenceGuide

499Testsuite

Page 500: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

useallJavaDSLmethodstothisdesignerinstance.Citruswillautomaticallyfindandexecutethebeforesuitelogic.WeonlyneedtoaddthisclasstotheSpringbeanapplicationcontext.Youcandothisexplicitly:

<beanid="myBeforeSuite"class="my.company.citrus.MyBeforeSuite"/>

OfcourseyoucanalsouseotherSpringbeanmechanismssuchascomponent-scansheretoo.TherespectivetestrunnerimplementationextendstheTestRunnerBeforeSuiteSupportandgetsatestrunnerinstanceasmethodargumentinjected.

JavaDSLrunner

publicclassMyBeforeSuiteextendsTestRunnerBeforeSuiteSupport@OverridepublicvoidbeforeSuite(TestRunnerrunner)runner.echo("Thisactionshouldbeexecutedbeforesuite");

Youcanhavemanybefore-suiteconfigurationcomponentswithdifferentidsinaCitrusproject.Bydefaultthecontainersarealwaysexecuted.Butyoucanrestricttheaftersuiteactioncontainerexecutionbydefiningasuitename,testgroupnames,environmentorsystempropertiesthatshouldmatchaccordingly:

XMLConfig

<citrus:before-suiteid="actionsBeforeSuite"suites="databaseSuite"groups="e2e"><citrus:actions><citrus-test:sqldataSource="testDataSource"/><citrus-test:statement>CREATETABLEPERSON(IDinteger,NAMEchar(250))</citrus-test:statement</citrus-test:sql></citrus:actions></citrus:before-suite>

TheabovebeforesuitecontainerisonlyexecutedwiththetestsuitecalleddatabaseSuiteorwhenthetestgroupe2eisdefined.TestgroupsandsuitenamesareonlysupportedwhenusingtheTestNGunittestframework.UnfortunatelyJUnitdoesnotallowtohookintosuiteexecutionaseasilyasTestNGdoes.Thisiswhyaftersuite

CitrusReferenceGuide

500Testsuite

Page 501: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

actioncontainersarenotrestrictedinexecutionwhenusingCitruswiththeJUnittestframework.Youcandefinemultiplesuitenamesandtestgroupswithcommadelimitedstringsasattributevalues.

WhenusingtheJavaDSLbeforesuitesupportyoucansetsuitenamesandtestgroupfiltersbysimplycallingtherespectivesettermethodsinyourcustomimplementation.

<beanid="myBeforeSuite"class="my.company.citrus.MyBeforeSuite"><propertyname="suiteNames"><list><value>databaseSuite</value></list></property><propertyname="testGroups"><list><value>e2e</value></list></property></bean>

Environmentorsystempropertiesaredefinedaslistofkey-valuepairs.Whenspecifiedthepropertieshavetobepresentwithrespectivevalue.Incasethepropertyvalueisleftoutinconfigurationthepropertymustsimplyexistsonthesysteminordertoenablethebeforesuitesequenceinthattestrun.

XMLConfig

<citrus:before-suiteid="actionsBeforeSuite"suites="databaseSuite"groups="e2e"><citrus:env><citrus:propertyname="USER"/></citrus:env><citrus:system><citrus:propertyname="test-stage"value="e2e"/></citrus:system><citrus:actions><citrus-test:sqldataSource="testDataSource"/><citrus-test:statement>CREATETABLEPERSON(IDinteger,NAMEchar(250))</citrus-test:statement</citrus-test:sql></citrus:actions></citrus:before-suite>

IntheexampleabovethesuitesequencewillonlyapplyonenvironmentswithUSERpropertysetandthesystempropertytest-stagemustbesettoe2e.Otherwisethesequenceexecutionisskipped.

CitrusReferenceGuide

501Testsuite

Page 502: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Aftersuite

Atestrunmayrequirethetestenvironmenttobeclean.ThereforeitisagoodideatopurgeallJMSdestinationsorcleanupthedatabaseafterthetestruninordertoavoiderrorsinfollow-uptestruns.Justlikewepreparedsomedatainactionsbeforesuitewecancleanupthetestruninactionsafterthetestsarefinished.TheSpringbeansyntaxhereisnotsignificantlydifferenttothoseinbeforesuitesection:

XMLConfig

<citrus:after-suiteid="actionsAfterSuite"><citrus:actions><!--listofactionsaftersuite--></citrus:actions></citrus:after-suite>

Againwegivetheaftersuiteconfigurationcomponentauniqueidwithintheconfigurationandputonetomanytestactionsasnestedconfigurationelementstothelistofactionsexecutedafterthetestsuiterun.

XMLConfig

<citrus:after-suiteid="actionsAfterSuite"><citrus:actions><citrus-test:sqldataSource="testDataSource"/><citrus-test:statement>DELETEFROMTABLEPERSON</citrus-test:statement></citrus-test:sql></citrus:actions></citrus:after-suite>

WehavetousetheCitrustestcaseXMLnamespacewhendefiningnestedtestactionsinaftersuitelist.Wejustremovealldatafromthedatabasesowedonotinfluencefollow-uptests.Quitesimpleisn'tit!?

OfcoursewecanalsodefineJavaDSLaftersuiteactions.YoucandothisbyaddingacustomclassthatextendsTestDesignerAfterSuiteSupportorTestRunnerAfterSuiteSupport.

JavaDSLdesigner

publicclassMyAfterSuiteextendsTestDesignerAfterSuiteSupport@OverridepublicvoidafterSuite(TestDesignerdesigner)designer.echo("Thisactionshouldbeexecutedaftersuite");

CitrusReferenceGuide

502Testsuite

Page 503: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ThecustomimplementationextendsTestDesignerAfterSuiteSupportandthereforehastoimplementthemethodafterSuite.ThismethodaddsomeJavaDSLdesignerlogictotheaftersuite.Thedesignerinstanceisinjectedasmethodargument.YoucanuseallJavaDSLmethodstothisdesignerinstance.Citruswillautomaticallyfindandexecutetheaftersuitelogic.WeonlyneedtoaddthisclasstotheSpringbeanapplicationcontext.Youcandothisexplicitly:

<beanid="myAfterSuite"class="my.company.citrus.MyAfterSuite"/>

OfcourseyoucanalsouseotherSpringbeanmechanismssuchascomponent-scansheretoo.TherespectivetestrunnerimplementationextendstheTestRunnerAfterSuiteSupportandgetsatestrunnerinstanceasmethodargumentinjected.

JavaDSLrunner

publicclassMyAfterSuiteextendsTestRunnerAfterSuiteSupport@OverridepublicvoidafterSuite(TestRunnerrunner)runner.echo("Thisactionshouldbeexecutedaftersuite");

Youcanhavemanyafter-suiteconfigurationcomponentswithdifferentidsinaCitrusproject.Bydefaultthecontainersarealwaysexecuted.Butyoucanrestricttheaftersuiteactioncontainerexecutionbydefiningasuitename,testgroupnames,environmentorsystempropertiesthatshouldmatchaccordingly:

XMLConfig

<citrus:after-suiteid="actionsAfterSuite"suites="databaseSuite"groups="e2e"><citrus:actions><citrus-test:sqldataSource="testDataSource"/><citrus-test:statement>DELETEFROMTABLEPERSON</citrus-test:statement></citrus-test:sql></citrus:actions></citrus:after-suite>

CitrusReferenceGuide

503Testsuite

Page 504: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TheaboveaftersuitecontainerisonlyexecutedwiththetestsuitecalleddatabaseSuiteorwhenthetestgroupe2eisdefined.TestgroupsandsuitenamesareonlysupportedwhenusingtheTestNGunittestframework.UnfortunatelyJUnitdoesnotallowtohookintosuiteexecutionaseasilyasTestNGdoes.ThisiswhyaftersuiteactioncontainersarenotrestrictedinexecutionwhenusingCitruswiththeJUnittestframework.

Youcandefinemultiplesuitenamesandtestgroupswithcommadelimitedstringsasattributevalues.

WhenusingtheJavaDSLbeforesuitesupportyoucansetsuitenamesandtestgroupfiltersbysimplycallingtherespectivesettermethodsinyourcustomimplementation.

<beanid="myAfterSuite"class="my.company.citrus.MyAfterSuite"><propertyname="suiteNames"><list><value>databaseSuite</value></list></property><propertyname="testGroups"><list><value>e2e</value></list></property></bean>

Environmentorsystempropertiesaredefinedaslistofkey-valuepairs.Whenspecifiedthepropertieshavetobepresentwithrespectivevalue.Incasethepropertyvalueisleftoutinconfigurationthepropertymustsimplyexistsonthesysteminordertoenablethebeforesuitesequenceinthattestrun.

XMLConfig

<citrus:after-suiteid="actionsBeforeSuite"suites="databaseSuite"groups="e2e"><citrus:env><citrus:propertyname="USER"/></citrus:env><citrus:system><citrus:propertyname="test-stage"value="e2e"/></citrus:system><citrus:actions><citrus-test:sqldataSource="testDataSource"/><citrus-test:statement>DELETEFROMTABLEPERSON</citrus-test:statement></citrus-test:sql></citrus:actions></citrus:after-suite>

CitrusReferenceGuide

504Testsuite

Page 505: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

IntheexampleabovethesuitesequencewillonlyapplyonenvironmentswithUSERpropertysetandthesystempropertytest-stagemustbesettoe2e.Otherwisethesequenceexecutionisskipped.

Beforetest

BeforeeachtestisexecuteditalsomightsoundreasonabletopurgeallJMSqueuesforinstance.IncaseaprevioustestfailssomemessagesmightbeleftintheJMSqueues.Alsothedatabasemightbeindirtystate.Thefollow-uptestthenwillbeconfrontedwiththeseinvalidmessagesanddata.PurgingallJMSdestinationsbeforeatestisthereforeagoodidea.Justlikewepreparedsomedatainactionsbeforesuitewecancleanupthedatabeforeateststartstoexecute.

XMLConfig

<citrus:before-testid="defaultBeforeTest"><citrus:actions><!--listofactionsbeforetest--></citrus:actions></citrus:before-test>

Thebeforetestconfigurationcomponentreceivesauniqueidandalistoftestactionsthatgetexecutedbeforeatestcaseisstarted.Thecomponentreceivesusualtestactiondefinitionsjustlikeyouwouldwritetheminanormaltestcasedefinition.Seetheexamplebelowhowtoaddtestactions.

XMLConfig

<citrus:before-testid="defaultBeforeTest"><citrus:actions><citrus-test:echo><citrus-test:message>Thisisexecutedbeforeeachtest!</citrus-test:message></citrus-test:echo></citrus:actions></citrus:before-test>

NotethatwemustusetheCitrustestcaseXMLnamespaceforthenestedtestactiondefinitions.YouhavetodeclaretheXMLnamespacesaccordinglyinyourconfigurationrootelement.Theechotestactionisnowexecutedbeforeeachtestinourtestsuiterun.

CitrusReferenceGuide

505Testsuite

Page 506: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Alsonoticethatwecanrestrictthebeforetestcontainerexecution.Wecanrestrictexecutionbasedonthetestname,package,testgroupsandenvironmentorsystemproperties.Seefollowingexamplehowthisworks:

XMLConfig

<citrus:before-testid="defaultBeforeTest"test="*_Ok_Test"package="com.consol.citrus.longrunning.*"<citrus:actions><citrus-test:echo><citrus-test:message>Thisisexecutedbeforeeachtest!</citrus-test:message></citrus-test:echo></citrus:actions></citrus:before-test>

Theabovebeforetestcomponentisonlyexecutedfortestcasesthatmatchthenamepattern*_Ok_Testandthatmatchthepackagecom.consol.citrus.longrunning.*.Alsowecouldjustusethetestnamepatternorthepackagenamepatternexclusively.Andtheexecutioncanberestrictedbasedontheincludedtestgroupsinourtestsuiterun.Thisenablesustospecifybeforetestactionsinvariousways.Ofcourseyoucanhavemultiplebeforetestconfigurationcomponentsatthesametime.Citruswillpicktherightcontainersandputittoexecutionwhennecessary.

Environmentorsystempropertiesaredefinedaslistofkey-valuepairs.Whenspecifiedthepropertieshavetobepresentwithrespectivevalue.Incasethepropertyvalueisleftoutinconfigurationthepropertymustsimplyexistsonthesysteminordertoenablethebeforesuitesequenceinthattestrun.

XMLConfig

<citrus:before-testid="specialBeforeTest"><citrus:env><citrus:propertyname="USER"/></citrus:env><citrus:system><citrus:propertyname="test-stage"value="e2e"/></citrus:system><citrus:actions><citrus-test:echo><citrus-test:message>Thisisexecutedbeforeeachtest!</citrus-test:message></citrus-test:echo></citrus:actions></citrus:before-test>

CitrusReferenceGuide

506Testsuite

Page 507: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

IntheexampleabovethetestsequencewillonlyapplyonenvironmentswithUSERpropertysetandthesystempropertytest-stagemustbesettoe2e.Otherwisethesequenceexecutionisskipped.

WhenusingtheJavaDSLweneedtoimplementthebeforetestlogicinaseparateclassthatextendsTestDesignerBeforeTestSupportorTestRunnerBeforeTestSupport

JavaDSLdesigner

publicclassMyBeforeTestextendsTestDesignerBeforeTestSupport@OverridepublicvoidbeforeTest(TestDesignerdesigner)designer.echo("Thisactionshouldbeexecutedbeforeeachtest");

AsyoucanseetheclassimplementsthemethodbeforeTestthatisprovidedwithatestdesignerargument.YousimplyaddthebeforetestactionstothedesignerinstanceasusualbycallingJavaDSLmethodsonthedesignerobject.Citruswillautomaticallyexecutetheseoperationsbeforeeachtestisexecuted.ThesamelogicappliestothetestrunnervariationthatextendsTestRunnerBeforeTestSupport:

JavaDSLrunner

publicclassMyBeforeTestextendsTestRunnerBeforeTestSupport@OverridepublicvoidbeforeTest(TestRunnerrunner)runner.echo("Thisactionshouldbeexecutedbeforeeachtest");

ThebeforetestimplementationsareaddedtotheSpringbeanapplicationcontextforgeneralactivation.YoucandothiseitherasexplicitSpringbeandefinitionorviapackagecomponent-scan.Hereisasampleforaddingthebeanimplementationexplicitlywithsomeconfiguration

<beanid="myBeforeTest"class="my.company.citrus.MyBeforeTest"><propertyname="packageNamePattern"value="com.consol.citrus.e2e"></property></bean>

CitrusReferenceGuide

507Testsuite

Page 508: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

WecanaddfilterpropertiestothebeforetestJavaDSLactionssotheyappliedtospecificpackagesortestnamepatterns.Theaboveexamplewillonlyapplytotestsinpackagecom.consol.citrus.e2e.Leavethesepropertiesemptyfordefaultactionsthatareexecutedbeforealltests.

Aftertest

Thesamelogicthatappliestothebefore-testconfigurationcomponentcanbedoneaftereachtest.Theafter-testconfigurationcomponentdefinestestactionsexecutedaftereachtest.Justlikewepreparedsomedatainactionsbeforeatestwecancleanupthedataafteratesthasfinishedexecution.

XMLConfig

<citrus:after-testid="defaultAfterTest"><citrus:actions><!--listofactionsaftertest--></citrus:actions></citrus:after-test>

Theaftertestconfigurationcomponentreceivesauniqueidandalistoftestactionsthatgetexecutedafteratestcaseisfinished.Noticethattheaftertestactionsareexecutednomatterwhatresultsuccessorfailuretheprevioustestcasecameupto.Thecomponentreceivesusualtestactiondefinitionsjustlikeyouwouldwritetheminanormaltestcasedefinition.Seetheexamplebelowhowtoaddtestactions.

XMLConfig

<citrus:after-testid="defaultAfterTest"><citrus:actions><citrus-test:echo><citrus-test:message>Thisisexecutedaftereachtest!</citrus-test:message></citrus-test:echo></citrus:actions></citrus:after-test>

PleasebeawareofthefactthatwemustusetheCitrustestcaseXMLnamespaceforthenestedtestactiondefinitions.YouhavetodeclaretheXMLnamespacesaccordinglyinyourconfigurationrootelement.Theechotestactionisnowexecutedaftereachtestinourtestsuiterun.Ofcoursewecanrestricttheaftertestcontainerexecution.Supportedrestrictionsarebasedonthetestname,package,testgroupsandenvironmentorsystemproperties.Seefollowingexamplehowthisworks:

CitrusReferenceGuide

508Testsuite

Page 509: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

XMLConfig

<citrus:after-testid="defaultAfterTest"test="*_Error_Test"package="com.consol.citrus.error.*"<citrus:actions><citrus-test:echo><citrus-test:message>Thisisexecutedaftereachtest!</citrus-test:message></citrus-test:echo></citrus:actions></citrus:after-test>

Theaboveaftertestcomponentisobviouslyonlyexecutedfortestcasesthatmatchthenamepattern*_Error_Testandthatmatchthepackagecom.consol.citrus.error.*.Alsowecouldjustusethetestnamepatternorthepackagenamepatternexclusively.Andtheexecutioncanberestrictedbasedontheincludedtestgroupsinourtestsuiterun.Thisenablesustospecifyaftertestactionsinvariousways.Ofcourseyoucanhavemultipleaftertestconfigurationcomponentsatthesametime.Citruswillpicktherightcontainersandputittoexecutionwhennecessary.

Environmentorsystempropertiesaredefinedaslistofkey-valuepairs.Whenspecifiedthepropertieshavetobepresentwithrespectivevalue.Incasethepropertyvalueisleftoutinconfigurationthepropertymustsimplyexistsonthesysteminordertoenablethebeforesuitesequenceinthattestrun.

XMLConfig

<citrus:after-testid="specialAfterTest"><citrus:env><citrus:propertyname="USER"/></citrus:env><citrus:system><citrus:propertyname="test-stage"value="e2e"/></citrus:system><citrus:actions><citrus-test:echo><citrus-test:message>Thisisexecutedaftereachtest!</citrus-test:message></citrus-test:echo></citrus:actions></citrus:after-test>

IntheexampleabovethetestsequencewillonlyapplyonenvironmentswithUSERpropertysetandthesystempropertytest-stagemustbesettoe2e.Otherwisethesequenceexecutionisskipped.

CitrusReferenceGuide

509Testsuite

Page 510: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

WhenusingtheJavaDSLweneedtoimplementtheaftertestlogicinaseparateclassthatextendsTestDesignerAfterTestSupportorTestRunnerAfterTestSupport

JavaDSLdesigner

publicclassMyAfterTestextendsTestDesignerAfterTestSupport@OverridepublicvoidafterTest(TestDesignerdesigner)designer.echo("Thisactionshouldbeexecutedaftereachtest");

AsyoucanseetheclassimplementsthemethodafterTestthatisprovidedwithatestdesignerargument.YousimplyaddtheaftertestactionstothedesignerinstanceasusualbycallingJavaDSLmethodsonthedesignerobject.Citruswillautomaticallyexecutetheseoperationsaftereachtestisexecuted.ThesamelogicappliestothetestrunnervariationthatextendsTestRunnerAfterTestSupport:

JavaDSLrunner

publicclassMyAfterTestextendsTestRunnerAfterTestSupport@OverridepublicvoidafterTest(TestRunnerrunner)runner.echo("Thisactionshouldbeexecutedaftereachtest");

TheaftertestimplementationsareaddedtotheSpringbeanapplicationcontextforgeneralactivation.YoucandothiseitherasexplicitSpringbeandefinitionorviapackagecomponent-scan.Hereisasampleforaddingthebeanimplementationexplicitlywithsomeconfiguration

<beanid="myAfterTest"class="my.company.citrus.MyAfterTest"><propertyname="packageNamePattern"value="com.consol.citrus.e2e"></property></bean>

WecanaddfilterpropertiestotheaftertestJavaDSLactionssotheyappliedtospecificpackagesortestnamepatterns.Theaboveexamplewillonlyapplytotestsinpackagecom.consol.citrus.e2e.Leavethesepropertiesemptyfordefaultactionsthatareexecutedafteralltests.

CitrusReferenceGuide

510Testsuite

Page 511: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

CitrusReferenceGuide

511Testsuite

Page 512: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

CustomizemetainformationTestcasesinCitrusareusuallyprovidedwithsomemetainformationliketheauthor’snameorthedateofcreation.InCitrusyouareabletoextendthistestcasemetainformationwithyourownveryspecificcriteria.

Bydefaultatestcasecomesshippedwithmetainformationthatlookslikethis:

<testcasename="PwdChange_OK_1_Test"><meta-info><author>Christoph</author><creationdate>2010-01-18</creationdate><status>FINAL</status><last-updated-by>Christoph</last-updated-by><last-updated-on>2010-01-18T15:00:00</last-updated-on></meta-info>

[...]</testcase>

Youcanquiteeasilyadddatatothissectioninordertomeetyourindividualtestingstrategy.Letushaveasimpleexampletoshowhowitisdone.

FirstofallwedefineacustomXSDschemadescribingthenewelements:

<?xmlversion="1.0"encoding="UTF-8"?><schemaxmlns="http://www.w3.org/2001/XMLSchema"xmlns:tns="http://www.citrusframework.org/samples/my-testcase-info"targetNamespace="http://www.citrusframework.org/samples/my-testcase-info"elementFormDefault="qualified">

<elementname="requirement"type="string"/><elementname="pre-condition"type="string"/><elementname="result"type="string"/><elementname="classification"type="string"/></schema>

Wehavefoursimpleelements(requirement,pre-condition,resultandclassification)alltypedasstring.Thesenewelementslatergointothetestcasemetainformationsection.

CitrusReferenceGuide

512Metainfo

Page 513: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

AfterweaddedthenewXMLschemafiletotheclasspathofourprojectweneedtoannouncetheschematoSpring.AsyoumightknowalreadyaCitrustestcaseisnothingelsebutasimpleSpringconfigurationfilewithcustomizedXMLschemasupport.IfweaddnewelementstoatestcaseSpringneedstoknowtheXMLschemaforparsingthetestcaseconfigurationfile.Seethespring.schemasfileusuallyplacedintheMETA-INF/spring.schemasinyourproject.

Thefilecontentforourexamplewilllooklikefollows:

http://www.citrusframework.org/samples/my-testcase-info/my-testcase-info.xsd=com/consol/citrus/schemas/my-testcase-info.xsd

Sonowwearefinallyreadytousethenewmeta-infoelementsinsidethetestcase:

<?xmlversion="1.0"encoding="UTF-8"?><spring:beansxmlns="http://www.citrusframework.org/schema/testcase"xmlns:spring="http://www.springframework.org/schema/beans"xmlns:custom="http://www.citrusframework.org/samples/my-testcase-info"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/testcasehttp://www.citrusframework.org/schema/testcase/citrus-testcase.xsdhttp://www.citrusframework.org/samples/my-testcase-infohttp://www.citrusframework.org/samples/my-testcase-info/my-testcase-info.xsd">

<testcasename="PwdChange_OK_1_Test"><meta-info><author>Christoph</author><creationdate>2010-01-18</creationdate><status>FINAL</status><last-updated-by>Christoph</last-updated-by><last-updated-on>2010-01-18T15:00:00</last-updated-on><custom:requirement>REQ10001</custom:requirement><custom:pre-condition>Existinguser,sufficientrights</custom:pre-condition><custom:result>Passwordresetindatabase</custom:result><custom:classification>PasswordChange</custom:classification></meta-info>

[...]</testcase></spring:beans>

NoteWeuseaseparatenamespacedeclarationwithacustomnamespaceprefix“custom”inordertodeclarethenewXMLschematoourtestcase.Ofcourseyoucanpickanamespaceurlandprefixthatfitsbestforyourproject.Asyouseeitisquiteeasy

CitrusReferenceGuide

513Metainfo

Page 514: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

toaddcustommetainformationtoyourCitrustestcase.Thecustomizedelementsmaybepreciousforautomaticreporting.XSLtransformationsforinstanceareabletoreadthosemetainformationelementsinordertogenerateautomatictestreportsanddocumentation.

YoucanalsodeclareournewXMLschemaintheEclipsepreferencessectionasuserspecificXMLcatalogentry.TheneventheschemacodecompletioninyourEclipseXMLeditorwillbeavailableforourcustomizedmeta-infoelements.

CitrusReferenceGuide

514Metainfo

Page 515: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Tracingincoming/outgoingmessagesAswedealwithmessagebasedinterfacesCitruswillsendandreceivealotofmessagesduringatestrun.NowwemaywanttoseethesemessagesinchronologicalorderastheywereprocessedbyCitrus.WecanenablemessagetracinginCitrusinordertosavemessagestothefilesystemforfurtherinvestigations.

Citrusoffersaneasywaytodebugallreceivedmessagestothefilesystem.YouneedtoenablesomespecificloggersandinterceptorsintheSpringapplicationcontext.

<beanclass="com.consol.citrus.report.MessageTracingTestListener"/>

JustaddthisbeantotheSpringconfigurationandCitruswilllistenforsentandreceivedmessagesforsavingthosetothefilesystem.Youwillfindfilesliketheseinthedefaulttest-outputfolderafterthetestrun:

Forexample:

logs/trace/messages/MyTest.msgslogs/trace/messages/FooTest.msgslogs/trace/messages/SomeTest.msgs

EachCitrustestwritesa.msgsfilecontainingallmessagesthatwentoverthewireduringthetest.Bydefaultthedebugdirectoryissettologs/trace/messages/relativetotheprojecttestoutputdirectory.Butyoucansetyourownoutputdirectoryintheconfiguration

<beanclass="com.consol.citrus.report.MessageTracingTestListener"><propertyname="outputDirectory"value="file:/path/to/folder"/></bean>

NoteAsthefilenamesdonotchangewitheachtestrunmessagetracingfilesmaybeoverwritten.Soyoueventuallyneedtosavethegeneratedmessagedebugfilesbeforerunninganothergroupoftestcases.

LetsseesomesampleoutputforatestcasewithmessagecommunicationoverSOAPHttp:

SendingSOAPrequest:

CitrusReferenceGuide

515Messagetracing

Page 516: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<?xmlversion="1.0"encoding="UTF-8"?><SOAP-ENV:Envelopexmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"<SOAP-ENV:Header><Operationxmlns="http://citrusframework.org/test">sayHello</Operation></SOAP-ENV:Header><SOAP-ENV:Body><ns0:HelloRequestxmlns:ns0="http://www.consol.de/schemas/samples/sayHello.xsd"><ns0:MessageId>0857041782</ns0:MessageId><ns0:CorrelationId>6915071793</ns0:CorrelationId><ns0:User>Christoph</ns0:User><ns0:Text>HelloWebServer</ns0:Text></ns0:HelloRequest></SOAP-ENV:Body></SOAP-ENV:Envelope>

======================================================================

ReceivedSOAPresponse:<?xmlversion="1.0"encoding="UTF-8"?><SOAP-ENV:Envelopexmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"<SOAP-ENV:Header/><SOAP-ENV:Body><ns0:HelloResponsexmlns:ns0="http://www.consol.de/schemas/samples/sayHello.xsd"><ns0:MessageId>0857041782</ns0:MessageId><ns0:CorrelationId>6915071793</ns0:CorrelationId><ns0:User>WebServer</ns0:User><ns0:Text>HelloChristoph</ns0:Text></ns0:HelloResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>

Forthismessagetracingtoworkweneedtoaddlogginglistenerstooursenderandreceivercomponentsaccordingly.

<citrus-ws:clientid="webServiceClient"request-url="http://localhost:8071"message-factory="messageFactory"interceptors="clientInterceptors"/>

<util:listid="clientInterceptors"><beanclass="com.consol.citrus.ws.interceptor.LoggingClientInterceptor"/></util:list>

ImportantBeawareofaddingtheSpringutilXMLnamespacetotheapplicationcontextwhenusingtheutil:listconstruct.

CitrusReferenceGuide

516Messagetracing

Page 517: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

CitrusReferenceGuide

517Messagetracing

Page 518: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ReportingandtestresultsTheframeworkgeneratesdifferentreportsandresultsafteratestrunforyou.Thesereportandresultpageswillhelpyoutogetanoverviewofthetestcasesthatwereexecutedandwhichonewerefailing.

Consolelogging

Duringthetestruntheframeworkwillprovideahugeamountofinformationthatisprintedouttotheconsole.Thisincludescurrenttestprogress,validationresultsanderrorinformation.Thisenablestheusertoquicklysupervisethetestrunprogress.Failuresintestswillbeprintedtotheconsolejustthetimetheerroroccurred.Thedetailedstacktraceinformationandthedetailederrormessagesarehelpfultogettheideawhatwentwrong.

Astheconsoleoutputmightbelimitedtoadefinedbufferlimit,theusermaynotbeabletofollowtheoutputtotheverybeginningofthetestrun.Thereforetheframeworkadditionallyprintsallinformationtoalogfileaccordingtotheloggingconfiguration.

TheloggingmechanismusestheSLF4Jloggingframework.SLF4Jisindependentofloggingframeworkimplementationsonthemarket.SoincaseyouuseLog4Jloggingframeworkthespecifiedlogfilepathaswellaslogginglevelscanbefreelyconfiguredintherespectivelog4j.xmlfileinyourproject.Attheendofatestrunthecombinedtestresultsgetprintedtobothconsoleandlogfile.Theoveralltestresultslooklikefollowingexample:

CITRUSTESTRESULTS

[...]HelloService_Ok_1:SUCCESSHelloService_Ok_2:SUCCESSEchoService_Ok_1:SUCCESSEchoService_Ok_2:SUCCESSEchoService_TempError_1:SUCCESSEchoService_AutomacticRetry_1:SUCCESS[...]

Found175testcasestoexecuteSkipped0testcases(0.0%)Executed175testcasesTestsfailed:0(0.0%)

CitrusReferenceGuide

518Reporting

Page 519: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Testssuccessfully:175(100.0%)

Failedtestswillbemarkedasfailedintheresultlist.Theframeworkwillgiveashortdescriptionoftheerrorcausewhilethedetailedstacktraceinformationcanbefoundinthelogmessagesthatweremadeduringthetestrun.

HelloService_Ok_3:failed-ExceptionisActiontimedout

JUnitreports

AstestsareexecutedasTestNGtestcases,theframeworkwillalsogenerateJUnitcompliantXMLandHTMLreports.JUnittestreportsareverypopularandfindsupportinmanybuildmanagementanddevelopmenttools.IngeneraltheCitrustestreportsgiveyouanoverallpictureofalltestsandtellyouwhichofthemwerefailing.

BuildmanagementtoolslikeJenkinscaneasilyimportanddisplaythegeneratedJUnitXMLresults.PleasehavealookattheTestNGandJUnitdocumentationformoreinformationaboutthistopicaswellasthebuildmanagementtools(e.g.Jenkins)tofindouthowtointegratethetestsresults.

HTMLreports

CitruscreatesHTMLreportsaftereachtestrun.Thereportprovidesdetailedinformationonthetestrunwithasummaryofalltestresults.Youcanfindthereportafteratestruninthedirectory$project.build.directory/test-output/citrus-reports.

Thereportconsistsoftwoparts.Thetestsummaryontopshowsthetotalnumberexecutedtests.Themainpartlistsalltestcaseswithdetailedinformation.Withthisreportyouimmediatelyidentifyallteststhatwerefailing.Eachtestcaseismarkedincoloraccordingtoitsresultoutcome.

ThefailedtestsgivedetailederrorinformationwitherrormessagesandJavaStackTraceinformation.InadditiontothatthereporttriestofindthetestactioninsidetheXMLtestpartthatfailedinexecution.Withthefailingcodesnippetyoucanseewheretheteststopped.

NoteJavaScriptshouldbeactiveinyourwebbrowser.Thisistoenablethedetailedinformationwhichcomestoyouinformoftooltipsliketestauthorordescription.IfyouwanttoaccessthetooltipsJavaScriptshouldbeenabledinyourbrowser.

CitrusReferenceGuide

519Reporting

Page 520: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TheHTMLreportsarecustomizablebysystemproperties.Usefollowingpropertiese.g.inyourcitrus.propertiesfile:

citrus.html.report.enabled:Enables/disablesHTMLreportgeneration(default=true).citrus.html.report.directory:Outputdirectorypath(default=$project.build.directory/test-output/citrus-reports).citrus.html.report.file:Filenameforthereportfile(default=citrus-test-results.html).citrus.html.report.template:TemplateHTMLfilewithplaceholdersforreportresults.citrus.html.report.detail.template:Templatefilefordetailedtestresults.citrus.html.report.logo:FileresourcepathpointingtoaimagethatisaddedtotopofHTMLreport.

TheHTMLreportisbasedonatemplatefilethatiscustomizabletoyourspecialneeds.Thedefaulttemplatescanbefoundinreport-templatessources.

CitrusReferenceGuide

520Reporting

Page 521: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

SamplesThischaptergivessomesampleswhereyoucanseeCitrusinaction.

samples-flightbooking

CitrusReferenceGuide

521Samples

Page 522: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TheFlightBookingsample

AsimpleprojectexampleshouldgiveyoutheideahowCitrusworks.Thesystemundertestisaflightbookingservicethathandlestravelrequestsfromatravelagency.Atravelrequestconsistsofacompletetravelrouteincludingseveralflights.TheFlightBookingServiceapplicationwillsplitthecompletetravelbookingintoseparateflightbookingsthataresenttotherespectiveairlinesincharge.Thebookingandcustomerdataispersistedinadatabase.

Theairlineswillconfirmordenytheflightbookings.TheFlightBookingServiceapplicationconsolidatesallincomingflightconfirmationsandcombinesthemtoacompletetravelconfirmationordenialthatissentbacktothetravelagency.Nextpicturetriestoputthearchitectureintographics:

InourexampletwodifferentairlinesareconnectedtotheFlightBookingServiceapplication:theSmartArilineoverJMSandtheRoyalAirlineoverHttp.

Theusecase

Theusecasethatwewouldliketotestisquitesimple.Thetestshouldhandleasimpletravelbookingandexpectapositiveprocessingtotheend.Thetestcaseneithersimulatesbusinesserrorsnortechnicalproblems.Nextpictureshowstheusecaseasasequencediagram.

CitrusReferenceGuide

522FlightBookingSample

Page 523: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Thetravelagencyputsatravelbookingrequesttowardsthesystem.Thetravelbookingcontainstwoseparateflights.Theflightrequestsarepublishedtotheairlines(SmartAirlineandRoyalAirline).Bothairlinesconfirmtheflightbookingswithapositiveanswer.Theconsolidatedtravelbookingresponseisthensentbacktothetravelagency.

Configurethesimulatedsystems

Citrussimulatesallsurroundingapplicationsintheirbehaviorduringthetest.Thesimulatedapplicationsare:TravelAgency,SmartAirlineandRoyalAirline.ThesimulatedsystemshavetobeconfiguredintheCitrusconfigurationfirst.TheconfigurationisdoneinSpringXMLconfigurationfiles,asCitrususesSpringtoglueallitsservicestogether.

FirstofallwehavealookattheTravelAgencyconfiguration.TheTravelAgencyisusingJMStoconnecttoourtestedsystem,soweneedtoconfigurethisJMSconnectioninCitrus.

<beanname="connectionFactory"class="org.apache.activemq.ActiveMQConnectionFactory"><propertyname="brokerURL"value="tcp://localhost:61616"/></bean>

<citrus-jms:endpointid="travelAgencyBookingRequestEndpoint"destination-name="$travel.agency.request.queue"/>

<citrus-jms:endpointid="travelAgencyBookingResponseEndpoint"destination-name="$travel.agency.response.queue"/>

CitrusReferenceGuide

523FlightBookingSample

Page 524: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ThisisallCitrusneedstosendandreceivemessagesoverJMSinordertosimulatetheTravelAgency.BydefaultallJMSmessagesendersandreceiversneedaconnectionfactory.ThereforeCitrusissearchingforabeannamed"connectionFactory".IntheexampleweconnecttoaActiveMQmessagebroker.AconnectiontootherJMSbrokerslikeTIBCOEMSorApacheActiveMQispossibletoobysimplychangingtheconnectionfactoryimplementation.

Theidentifiersofthemessagesendersandreceiversareveryimportant.Weshouldthinkofsuitableidsthatgivethereaderafirsthintwhatthesender/receiverisusedfor.AswewanttosimulatetheTravelAgencyincombinationwithsendingbookingrequestsouridis"travelAgencyBookingRequestEndpoint"forexample.

ThesenderandreceiversdoalsoneedaJMSdestination.Herethedestinationnamesareprovidedbypropertyexpressions.TheSpringIoCcontainerresolvesthepropertiesforus.AllweneedtodoispublishthepropertyfiletotheSpringcontainerlikethis.

<beanname="propertyLoader"class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><propertyname="locations"><list><value>citrus.properties</value></list></property><propertyname="ignoreUnresolvablePlaceholders"value="true"/></bean>

Thecitrus.propertiesfileislocatedinourproject'sresourcesfolderanddefinestheactualqueuenamesbesidesotherpropertiesofcourse:

#JMSqueuestravel.agency.request.queue=Travel.Agency.Request.Queuetravel.agency.response.queue=Travel.Agency.Response.Queuesmart.airline.request.queue=Smart.Airline.Request.Queuesmart.airline.response.queue=Smart.Airline.Response.Queueroyal.airline.request.queue=Royal.Airline.Request.Queue

WhatelsedoweneedinourSpringconfiguration?TherearesomebasicbeansthatarecommonlydefinedinaCitrusapplicationbutIdonotwanttoboreyouwiththesedetails.SoifyouwanttohavealookattheSpringapplicationcontextfileintheresourcesfolderandseehowthingsaredefinedthere.

CitrusReferenceGuide

524FlightBookingSample

Page 525: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

WecontinuewiththefirstairlinetobeconfiguredtheSmartAirline.TheSmartAirlineisalsousingJMStocommunicatewiththeFlightBookingService.Sothereisnothingnewforus,wesimplydefineadditionalJMSmessagesendersandreceivers.

<citrus-jms:endpointid="smartAirlineBookingRequestEndpoint"destination-name="$smart.airline.request.queue"/>

<citrus-jms:endpointid="smartAirlineBookingResponseEndpoint"destination-name="$smart.airline.response.queue"/>

WedonotdefineanewJMSconnectionfactorybecauseTravelAgencyandSmartAirlineareusingthesamemessagebrokerinstance.Incaseyouneedtohandlemultipleconnectionfactoriessimplydefinetheconnectionfactorywiththeattribute"connection-factory".

<citrus-jms:endpointid="smartAirlineBookingRequestEndpoint"destination-name="$smart.airline.request.queue"connection-factory="smartAirlineConnectionFactory"/>

<citrus-jms:endpointid="smartAirlineBookingResponseEndpoint"destination-name="$smart.airline.response.queue"connection-factory="smartAirlineConnectionFactory"/>

ConfiguretheHttpadapter

TheRoyalAirlineisconnectedtooursystemusingHttprequest/responsecommunication.ThismeanswehavetosimulateaHttpserverinthetestthatacceptsclientrequestsandprovidesproperresponses.CitrusoffersaHttpserverimplementationthatwilllistenonaportforclientrequests.TheadapterforwardsincomingrequesttothetestengineoverJMSandreceivesaproperresponsethatisforwardedasaHttpresponsetotheclient.Thenextpictureshowsthismechanismindetail.

TheRoyalAirlineadapterreceivesclientrequestsoverHttpandsendsthemoverJMStoamessagereceiveraswealreadyknowit.Thetestenginevalidatesthereceivedrequestandprovidesaproperresponsebacktotheadapter.Theadapterwilltransform

CitrusReferenceGuide

525FlightBookingSample

Page 526: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

theresponsetoHttpagainandpublishesittothecallingclient.CitrusoffersthesekindofadaptersforHttpandSOAPcommunication.BywritingyourownadapterslikethisyouwillbeabletoextendCitrussoitworkswithprotocolsthatarenotsupportedyet.

LetusdefinetheHttpadapterintheSpringconfiguration:

<citrus-http:serverid="royalAirlineHttpServer"port="8091"uri="/flightbooking"endpoint-adapter="jmsEndpointAdapter"/>

<citrus-jms:endpoint-adapterid="jmsEndpointAdapterdestination-name="$royal.airline.request.queue"/>connection-factory="connectionFactory"/>timeout="2000"/>

<citrus-jms:sync-endpointid="royalAirlineBookingEndpoint"destination-name="$royal.airline.request.queue"/>

WeneedtoconfigureaHttpserverinstancewithaport,arequestURIandtheendpointadapter.WedefinetheJMSendpointadaptertohandlerequestasdescribed.InAdditiontotheendpointadapterwealsoneedsynchronousJMSmessagesenderandreceiverinstances.That'sit!WeareabletoreceiveHttprequestinordertosimulatetheRoyalAirlineapplication.Whatismissingnow?Thetestcasedefinitionitself.

Thetestcase

ThetestcasedefinitionisalsoaSpringconfigurationfile.CitrusoffersacustomizedXMLsyntaxtodefineatestcase.ThisXMLtestdefininglanguageissupposedtobeeasytounderstandandmorespecifictothedomainwearedealingwith.Nextlistingshowsthewholetestcasedefinition.Keepinmindthatatestcasedefineseverystepintheusecase.Sowedefinesendingandreceivingactionsoftheusecaseasdescribedinthesequencediagramwesawearlier.

<?xmlversion="1.0"encoding="UTF-8"?><spring:beansxmlns="http://www.citrusframework.org/schema/testcase"xmlns:spring="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.citrusframework.org/schema/testcasehttp://www.citrusframework.org/schema/testcase/citrus-testcase.xsd"><testcasename="FlightBookingTest"><meta-info>

CitrusReferenceGuide

526FlightBookingSample

Page 527: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<author>ChristophDeppisch</author><creationdate>2009-04-15</creationdate><status>FINAL</status><last-updated-by>ChristophDeppisch</last-updated-by><last-updated-on>2009-04-15T00:00:00</last-updated-on></meta-info><description>Testflightbookingservice.</description><variables><variablename="correlationId"value="citrus:concat('Lx1x','citrus:randomNumber(10)')"/><variablename="customerId"value="citrus:concat('Mx1x',citrus:randomNumber(10))"/></variables><actions><sendendpoint="travelAgencyBookingRequestEndpoint"><message><data><![CDATA[<TravelBookingRequestMessagexmlns="http://www.consol.com/schemas/TravelAgency"><correlationId>$correlationId</correlationId><customer><id>$customerId</id><firstname>John</firstname><lastname>Doe</lastname></customer><flights><flight><flightId>SM1269</flightId><airline>SmartAirline</airline><fromAirport>MUC</fromAirport><toAirport>FRA</toAirport><date>2009-04-15</date><scheduledDeparture>11:55:00</scheduledDeparture><scheduledArrival>13:00:00</scheduledArrival></flight><flight><flightId>RA1780</flightId><airline>RoyalAirline</airline><fromAirport>FRA</fromAirport><toAirport>HAM</toAirport><date>2009-04-15</date><scheduledDeparture>16:00:00</scheduledDeparture><scheduledArrival>17:10:00</scheduledArrival></flight></flights></TravelBookingRequestMessage>]]></data></message>

CitrusReferenceGuide

527FlightBookingSample

Page 528: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<header><elementname="correlationId"value="$correlationId"/></header></send>

<receiveendpoint="smartAirlineBookingRequestEndpoint"><message><data><![CDATA[<FlightBookingRequestMessagexmlns="http://www.consol.com/schemas/AirlineSchema"><correlationId>$correlationId</correlationId><bookingId>???</bookingId><customer><id>$customerId</id><firstname>John</firstname><lastname>Doe</lastname></customer><flight><flightId>SM1269</flightId><airline>SmartAirline</airline><fromAirport>MUC</fromAirport><toAirport>FRA</toAirport><date>2009-04-15</date><scheduledDeparture>11:55:00</scheduledDeparture><scheduledArrival>13:00:00</scheduledArrival></flight></FlightBookingRequestMessage>]]></data><ignorepath="//:FlightBookingRequestMessage/:bookingId"/></message><header><elementname="correlationId"value="$correlationId"/></header><extract><messagepath="//:FlightBookingRequestMessage/:bookingId"variable="$smartAirlineBookingId"/></extract></receive>

<sendendpoint="smartAirlineBookingResponseEndpoint"><message><data><![CDATA[<FlightBookingConfirmationMessagexmlns="http://www.consol.com/schemas/AirlineSchema"><correlationId>$correlationId</correlationId><bookingId>$smartAirlineBookingId</bookingId><success>true</success><flight><flightId>SM1269</flightId>

CitrusReferenceGuide

528FlightBookingSample

Page 529: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<airline>SmartAirline</airline><fromAirport>MUC</fromAirport><toAirport>FRA</toAirport><date>2009-04-15</date><scheduledDeparture>11:55:00</scheduledDeparture><scheduledArrival>13:00:00</scheduledArrival></flight></FlightBookingConfirmationMessage>]]></data></message><header><elementname="correlationId"value="$correlationId"/></header></send>

<receiveendpoint="royalAirlineBookingEndpoint"><message><data><![CDATA[<FlightBookingRequestMessagexmlns="http://www.consol.com/schemas/FlightBooking/AirlineSchema"><correlationId>$correlationId</correlationId><bookingId>???</bookingId><customer><id>$customerId</id><firstname>John</firstname><lastname>Doe</lastname></customer><flight><flightId>RA1780</flightId><airline>RoyalAirline</airline><fromAirport>FRA</fromAirport><toAirport>HAM</toAirport><date>2009-04-15</date><scheduledDeparture>16:00:00</scheduledDeparture><scheduledArrival>17:10:00</scheduledArrival></flight></FlightBookingRequestMessage>]]></data><ignorepath="//:FlightBookingRequestMessage/:bookingId"/></message><header><elementname="correlationId"value="$correlationId"/></header><extract><messagepath="//:FlightBookingRequestMessage/:bookingId"variable="$royalAirlineBookingId"/></extract></receive>

CitrusReferenceGuide

529FlightBookingSample

Page 530: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<sendendpoint="royalAirlineBookingEndpoint"><message><data><![CDATA[<FlightBookingConfirmationMessagexmlns="http://www.consol.com/schemas/AirlineSchema"><correlationId>$correlationId</correlationId><bookingId>$royalAirlineBookingId</bookingId><success>true</success><flight><flightId>RA1780</flightId><airline>RoyalAirline</airline><fromAirport>FRA</fromAirport><toAirport>HAM</toAirport><date>2009-04-15</date><scheduledDeparture>16:00:00</scheduledDeparture><scheduledArrival>17:10:00</scheduledArrival></flight></FlightBookingConfirmationMessage>]]></data></message><header><elementname="correlationid"value="$correlationId"/></header></send>

<receiveendpoint="travelAgencyBookingResponseEndpoint"><message><data><![CDATA[<TravelBookingResponseMessagexmlns="http://www.consol.com/schemas/TravelAgency"><correlationId>$correlationId</correlationId><success>true</success><flights><flight><flightId>SM1269</flightId><airline>SmartAirline</airline><fromAirport>MUC</fromAirport><toAirport>FRA</toAirport><date>2009-04-15</date><scheduledDeparture>11:55:00</scheduledDeparture><scheduledArrival>13:00:00</scheduledArrival></flight><flight><flightId>RA1780</flightId><airline>RoyalAirline</airline><fromAirport>FRA</fromAirport><toAirport>HAM</toAirport><date>2009-04-15</date><scheduledDeparture>16:00:00</scheduledDeparture>

CitrusReferenceGuide

530FlightBookingSample

Page 531: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

<scheduledArrival>17:10:00</scheduledArrival></flight></flights></TravelBookingResponseMessage>]]></data></message><header><elementname="correlationId"value="$correlationId"/></header></receive>

</actions></testcase></spring:beans>

Similartoasequencediagramthetestcasedescribeseverystepoftheusecase.Attheverybeginningthetestcasegetsnameanditsmetainformation.Followingwiththevariablevaluesthatareusedalloverthetest.HereitisthecorrelationIdandthecustomerIdthatareusedastestvariables.Insidemessagetemplatesheadervaluesthevariablesarereferencedseveraltimesinthetest

<correlationId>$correlationId</correlationId><id>$customerId</id>

Thesending/receivingactionsuseapreviouslydefinedmessagesender/receiver.ThisisthelinkbetweentestcaseandbasicSpringconfigurationwehavedonebefore.

sendendpoint="travelAgencyBookingRequestEndpoint"

Thesendingactionchoosesamessagesendertoactuallysendthemessageusingamessagetransport(JMS,Http,SOAP,etc.).Aftersendingthisfirst"TravelBookingRequestMessage"requestthetestcaseexpectsthefirst"FlightBookingRequestMessage"messageontheSmartAirlineJMSdestination.Incasethismessageisnotarrivingintimethetestwillfailwitherrors.InpositivecaseourFlightBookingServiceworkswellandthemessagearrivesintime.Thereceivedmessageisvalidatedagainstadefinedexpectedmessagetemplate.Onlyincaseallcontentvalidationstepsaresuccessfulthetestcontinueswiththeactionchain.Andsothetestcaseproceedsandworksthroughtheusecaseuntileverymessageissentrespectivelyreceivedandvalidated.Theusecaseisdoneautomaticallywithouthumaninteraction.Citrussimulatesallsurroundingapplicationsandprovidesdetailedvalidationpossibilitiesofmessages.

CitrusReferenceGuide

531FlightBookingSample

Page 532: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

CitrusReferenceGuide

532FlightBookingSample

Page 533: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

AppendixThischaptergivesabriefoverviewofallarchivedchanges.

Changes2.5Changes2.4Changes2.3Changes2.2Changes2.1Changes2.0Changes1.4Changes1.3Changes1.2

CitrusReferenceGuide

533Appendix

Page 534: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ChangesinCitrus2.6Citrus2.6comeswithasetofnewmodulesthatenablecompletelynewaspectsofintegrationtesting.NamelythesearethenewmodulesforCucumberbehaviordrivendevelopmentandZookeepersupport.Justhavealookatthefollowingfeaturesthatareshippedwithinthe2.6box.

Gzipcompression

CitrusnowsupportsGzipmessagecompression.ForHttpclientserverendpointsweintroducedspecialcompressionfiltersthatautomaticallytakcareoncompressionwhenthehttpheaderAccept-Encoding=gziporContent-Encoding=gzipisset.Forotherendpointsweintroducedthemessagetypegzipandthemessagevalidatorgzip-base64whichautomaticallycompressesanddecompressesmessagepayloadsandenablesbase64Stringcomparisonforvalidationpurpose.Thenewcompressionfeaturesaredescribedinhttpandvalidation-gzip.

Customservletfilters

TheCitrushttpservercomponentnowacceptscustomservletfilterimplementations.Thisisusefulforimplementingcustomlogiconrequest/responseprocessingsuchasautomaticmessagecompressionorcaching.Youcansetoneormanycustomfilterimplementationsandmapthosetorequestpathsfortheserver.Readaboutthisinchapterhttp.

Escapetestvariablesyntax

Citrususestestvariablesandlooksfortheexpressionsoftype$variable-name.NowwhenthissamesyntaxispartofamessagecontentwerunintoerrorsasCitruswantstofindatestvariable.AttheendCitruscomplainsabouttheunknownvariable.ThereforeweintroducedanescapesyntaxforvariablessoyoucanskiptheCitrusvariableexpressionevaluation.Youcandothisbyusing$//escaped//syntax.Readmoreaboutthisintest-variables.

ConfigurableXMLserializer

CitrusReferenceGuide

534Changes2.6

Page 535: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

WeoftendealwithXMLmessageformatandthereforeneedtoparseandserializeXMLdata.ThedefaultXMLserializerusesprettyprintformatandcdatasectionsupport.Nowsometimesitismandatorytocustomizethesesettingswhichispossiblewiththenewversion.YoucanaddacustomXMLserializerintheSpringapplicationcontextandCitruswillautomaticallyusethisimplementationandconfiguration.Youcanseehowitworksinchaptervalidation-xml.

Localmessagestore

Weintroducedalocalmessagestorethatautomaticallysavesallexchangedmessages(inboundandoutbound).Thismessagestorecanbeusedtogetexchangedmessagesduringandafterthetest.Testactionsaswellastestlistenerscanaccessthelocalmessagestore.Readmoreaboutthisinchaptersendpoints,actions-sendandactions-receive.

Waitmessagecondition

Thewaittestactionhasanewcondition.Besideswaitingforfilestoexistandhttprequeststoberespondedyoucannowwaitformessagesinthelocalmessagestore.Thiswayyoucanwaitforacertainmessagetoarrive.Thisisdescribedinchapteractions-wait.

XpathandJsonPathFunction

TherearenewfunctionsavailabletoevaluatesomeXpathorJsonPathexpressiononaXML/Jsonsource.Thesourcecanbeastaticstructurecomingfromanexternalfileoramessagepayloadstoredinthelocalstorage.Seehowtousethisfunctionsinchapterfunctions.

Staticresponseadaptervariablessupport

Servercomponentscanusestaticresponseadaptersthatautomaticallysendresponsemessagestoanycallingclient.Theresponseadapterisnowabletousetestvariablesandfunctions.InadditiontothatyoucanmapvaluesfromtheactualrequestmessagethathastriggeredtheresponseadapterbyusingthelocalmessagestoreincombinationwithXpathorJsonPath.Readaboutthisinendpoint-adapter.

CucumberBDDsupport

CitrusReferenceGuide

535Changes2.6

Page 536: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Behaviordrivendevelopmentismoreandmorecomingupalsointheintegrationtestingenvironment.CucumberisafantasticbehaviordrivendevelopmentlibrarythatprovidessupportforBDDconceptswithGherkin.ThenewCitrusintegrationwithCucumberenablesthemixofGherkinsyntaxfeaturescenarioswithCitrustestcaseexecution.YouwritefeaturestoriesasusualandcreateCitrustestcaseswithlotsofactionsfortheintegrationtest.Seedetailsforthisfeatureincucumber.

Zookeepersupport

ZookeeperfromApacheletsyoumanageconfigurationwithdistributedcoordination.AsauseryoucreateandeditvaluesonaZookeeperserver.Otherclientsthencanretrievethisinformation.WithCitrusyouareabletoaccessthisinformationfromwithinatestcase.TheZookeeperCitrusclientletsyoumanageinformationontheZookeeperserver.Seedetailsforthisfeatureinzookeeper.

SpringRestdocssupport

RestdocsisafantasticwayofgeneratingdocumentationforRESTfulAPIs.Whileexchangingrequest/responsedatawiththeserverRestdocscreatesdocumentationinformationonthedata.Thedocumentationincludesfielddescriptions,headersandsnippetsforbodycontent.WithnewCitrusversionHttpclientsinCitruscanaddRestdocinterceptorsthatgeneratethedocumentationwhileexecutingthetestcases.Thiswayyouareabletodocumentwhatmessageswereexchangedintests.TheRestdocssupportisalsoavailablefortheSOAPHttpclientinCitrus.Seedetailsinrestdocs.

Hamcrestmatcherconditions

IteratingtestactioncontainersinCitrusevaluatebooleanexpressionsfordeterminationofhowtoexecutethenestedactionsinaloop.Alsotheconditionalcontainerexecutesnestedactionsbasedonbooleanexpressionevaluation.TheCitrusbooleanexpressionsupportislimitedtoverybasicoperationssuchaslowerthanorgreaterthan.Furthermorethecombinationofbooleanexpressionswithvariableshasnotbeensupported.FollowingfromthatwehaveimprovedthebooleanexpressionevaluationmechanismwithextensiontoHamcrestmatchers.Sonowyoucanevaluatematchersiniteratingconditions.Thisfeatureisdescribedincontainers-conditionalandcontainers-iterate.

SOAPJavaDSL

CitrusReferenceGuide

536Changes2.6

Page 537: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

CitrusprovidesanewJavafluentAPIforsendingandreceivingSOAPrelatedmessagecontent.TheJavaDSLenhancementsarebasedonthoseofHttp.NowyoucandefineSOAPmessageswithspecialSOAPactionheadersmoreeasily.OntopofthatyoucanhandleSOAPfaultsonclientandserverwiththefluentAPI.Checkoutsoap-webservicesfordetails.

Refactoring

Refactoringintermsofsimplificationandstandardizationispartofourdailylifeasadeveloper.WehavebeenworkingonimprovingtheJavaDSLfluentAPIforSOAP.Wealsointroducedamorecommonwayofhandlingthetestactioncontainerslikeiterate,parallelandsoon.Thisleadstosomeclassesandmethodsthatweremarkedasdeprecated.SopleasehavealookatyourJavaDSLcodeandifyouseesomeusageofdeprecatedstuffpleaseusethenewapproachesassoonaspossible.Thedeprecatedstuffwilldefinitelydisappearinupcomingreleases.

Someofthechangesthatwehavemademighthityourightaway.Thesechangesare:

ws:assertelementinSOAPtestcaseschemahasbeenrenamedtows:assert-fault.Thiswasdoneforbetterinteroperabilityreasonswithassertactionincoreschemaandtobecomplianttosend-faultaction.

JavaDSLmodulehashadMavendependenciestoseveralothermodulesinCitrus(e.g.citrus-jms,citrus-soap).Thesedependenciesweredeclaredascompiledependencies,whichisnotveryniceasyoumightnotneedJMSorSOAPfunctionalitiesinyourproject.Wehaveaddedoptionalandprovidedmarkerstothatdependencieswhichmeansthatyouhavetodecideinyourprojectwhichofthemodulestoinclude.

YoumayfacesomemissingdependencieserrorswhenrunningtheMavenproject.AsaresultyouneedtoincludetheCitrusmodules(e.g.citrus-http,citrus-docker,andsoon)inyourprojectMavenPOMexplicitly.

CitrusReferenceGuide

537Changes2.6

Page 538: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ChangesinCitrus2.5WehaveaddedlotsofnewfeaturesandimprovementswithCitrus2.5.NamelythesearethenewmodulesforRMIandJMXsupport,anewx-www-form-urlencodedmessagevalidatorandnewfunctionsanctestactions.Justhavealookatthefollowingfeaturesthatmadeittothebox.

Hamcrestmatchersupport

Hamcrestisaverypowerfulmatcherlibrarythatprovidesafantasticsetofmatcherimplementationsformessagevalidationpurpose.CitrusnowsupportsthesematcherscomingfromHamcrestlibrary.OntheonehandyoucanuseHamcrestmatchersasaCitrusvalidationmatcherasdescribedinvalidation-matcher-hamcrest.OntheotherhandyoucanuseHamcrestmatchersnowdirectlyusingtheCitrusJavaDSL.Seedetailsforthisfeatureinjson-path-validate.

Binarybase64messagevalidator

Thereisanewmessagevalidatorimplementationthatautomaticallyconvertsbinarymessagecontenttoabase64encodedStringrepresentationforcomparison.Thisistheeasiestwaytocomparebinarymessagecontentwithanexpectedmessagepayload.Seevalidation-binaryhowthisisworkingforyou.

RMIsupport

RemotemethodinvocationisastandardJavatechnologyandAPIforcallingmethodsonremoteobjectsacrossdifferentJVMinstances.AlthoughRMIhaslostitspopularityitisstillusedinlegacycomponents.TestingRMIbeaninvocationisahardthingtodo.NowCitrusprovidesclientandserversupportforremoteinterfaceinvocation.Seermifordetails.

JMXsupport

SimilartoRMIJMXcanbeusedtoconnecttoremotebeaninvocation.ThistimeweexposesomebeanstoamanagedbeanserverinordertobemanagedbyJMXoperationsforreadandwrite.WithCitrus2.5wehaveaddedaclientandserversupportforcallingandprovidingmanagedbeansonambeanserver.Seejmxfordetails.

CitrusReferenceGuide

538Changes2.5

Page 539: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Resourceinjection

With2.5wehaveaddedmechanismsforinjectingCitruscomponentstoyourJavaDSLtestmethods.ThisisveryusefulwhenneedingaccesstotheCitrustestcontextforinstance.Alsoweareabletousenewinjectionoftestdesignerandrunnerinstancesinordertosupportparalleltestexecutionwithmultiplethreads.Seetheexplanationsintestcase-resource-injectionandtestcase-context-injection.

Httpx-www-form-urlencodedmessagevalidator

HTMLformdatacanbetransmittedwithdifferentmethodsandcontenttypes.Oneofthemostcommonwaysistousex-www-form-urlencodedformdatacontent.Asvalidationcanbetrickywehaveaddedaspecialmessagevalidatorforthat.Seehttp-www-form-urlencodedfordetails.

Daterangevalidationmatcher

Addedanewvalidationmatcherimplementationthatisabletocheckthatadatevalueisbetweenacertaindaterange(fromandto)Thedaterangeisabletofocusondaysaswellasadditionaltime(hour,minute,second)specifications.Seevalidation-matcher-daterangefordetails.

Readfileresourcefunction

Anewfunctionimplementationoffersyouthepossibilitiestoreadfileresourcecontentsasinlinedata.Thefunctioniscalledandreturnsthefilecontentasreturnvalue.Thefilecontentisthenplacedrightwherethefunctionwascallede.g.insideofamessagepaylaodelementorasmessageheadervalue.Seefunctions-read-filefordetails.

Timercontainer

Thenewtimertestactioncontainerrepeatsitsexecutionbasedonatimeexpression(e.g.every5seconds).Withthistimerwecanrepeattestactionswithafixedtimedelayorconstantlyexecutetestactionswithtimeschedule.Seecontainers-timerandactions-stop-timerfordetails.

UpgradetoVert.x3.2.0

CitrusReferenceGuide

539Changes2.5

Page 540: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

TheVert.xmodulewasupgradedtouseVert.x3.2.0version.TheCitrusmoduleimplementationwasupdatedtoworkwiththisnewVert.xversion.LearnmoreabouttheVert.xintegrationinCitruswithvertx.

CitrusReferenceGuide

540Changes2.5

Page 541: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ChangesinCitrus2.4Citrus2.4comeswithasetofnewfeaturesespeciallyregardingApacheCamelandDockerintegrations.Bugfixesofcoursearealsopartofthepackage.Seethefollowingoverviewonwhathaschanged.

Dockersupport

DockerandMicroservicesarefrequenttopicsinsoftwaredevelopmentrecently.WehaveaddedinteractionwithDockerinCitrussotheusercanmanageDockercontainerswithinatestcase.CitrusnowprovidesspecialDockertestactionsforbuilding,starting,stoppingandinspectingDockerimagesandcontainersinatest.Seedockerfordetails.

HttpRESTactions

WehavesignificantlyimprovedtheHttpRESTsupportinCitrus.ThefocusisonsimplifyingtheHttpRESTusageinCitrustestcases.WithnewHttpspecifictestactionsonclientandserverwecansendandreceiveHttpRESTmessagesveryeasy.Seehttpfordetails.

Waittestaction

Withthenewwaittestactionwecanexplicitlywaitforsomeremoteconditiontobecometrueinsideofatestcase.TheconditionssupportedatthemomentareHttpurlrequestsandfilebasedconditions.AusercaninvokeaHttpserverurlandwaitforittoreturnasuccessHttp200OKresponse.Thisisanawesomefeaturewhenwaitingforaservertostartupbeforethetestcontinues.WecanalsothinkofwaitingforaDockercontainertostartupbeforecontinuing.Oryoucanwaituntilafileispresentonthelocalfilesystem.Seeactions-waitfordetails.

Camelactions

CitrushasalreadyhadsupportforApacheCamelroutesandCamelcontextloading.Nowwith2.4versionwehaveaddedsomespecialApacheCameltestactionsforinteractingwithaCamelcontextanditsroutes.ThisenablesthetestertocreateanduseanewCamelrouteontheflyinsideatestcase.AlsoCitrusisnowabletointeractwith

CitrusReferenceGuide

541Changes2.4

Page 542: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

theCamelcontrolbusaccessingroutestatisticsandstatusinformation.Alsopossiblearestart,stop,suspend,resumeoperationsonaCamelroute.Seecamel-actionsandcamel-controlbusfordetails.

Purgeendpointsaction

PurgingJMSqueuesandinmemorychannelsattestruntimehasbecomeawidelyusedfeatureespeciallywhenaimingtomaketestsmorestableintermsofindependenttests.Wehaveaddedapurgeendpointtestactionthatworksonanyconsumerendpoint.Soyoudonotneedtoseparatebetweenendpointimplementationsanymoreandmoreimportantyoucanpurgeserverinmemorychannelcomponentsveryeasy.Seeactions-purge-endpointsfordetails.

ReleasetoMavenCentral

Thisisnotanewfeaturebutalsoworthtotellhereasitisasignificantimprovementonthewholeframeworkproject.WecannowreleasetheCitrusartifactstoMavencentralrepository.Soyoudonotneedtheadditionallabs.consol.derepositoryinyourMavenPOManymore.Thelabs.consol.derepositorywillcontinuetoexistthoughaswewillreleaseSNAPSHOTversionsofCitrushereinfuture.

CitrusReferenceGuide

542Changes2.4

Page 543: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ChangesinCitrus2.3WewanttogiveyouashortoverviewofwhathaschangedinCitrus2.3.Thereleaseaddssomenewfeaturesandimprovementstothebox.Bugfixesofcoursearealsopartofthepackage.Seethefollowingoverviewonwhathaschanged.

Testrunnerandtestdesigner

OneofthebiggestissueswiththeCitrusJavaDSListhefactthattheCitrusJavaDSLmethodsfirstbuildthewholetestcasetogetherbeforetheactualexecutiontakesplace.SocallingaJavaDSLmethodsendforinstancejustpreparesthesendingtestaction.Theactualsendingofthemessagetakesplacetoalatertimewhenalltestactionsaresetupandthetestcaseisreadytorun.ThisseparationofdesigntimeandruntimeofatestcaseleadstomisunderstandingsasaJavadeveloperisusedtoworkwithstatementsandmethodcallsthatperformimmediately.BasedonthatthemixtureofCitrusJavaDSLmethodcallsandnormalJavacodelogicinyourtestmayhaveleadtounexpectedbehavior.FollowingfromthatwedecidedtorefactortheJavaDSLmethodexecution.TheresultisanewTestRunnerconceptthatexecutesallJavaDSLmethodcallsimmediately.TheoldwayofbuildingthewholetestcasebeforeexecutionisrepresentedwithTestDesignerconcept.Sobothworldsarenowavailabletoyou.Seetestcasefordetails.

WebSocketsupport

TheWebSocketmessageprotocolbuildsontopofHttpstandardandbringsbidirectionalcommunicationtotheHttpclient-serverworld.WiththisreleaseCitrususersareabletosendandreceivemessageswithWebSocketconnections.TheHttpserverimplementationisnowabletodefinemultipleWebSocketendpoints.ThenewCitrusWebSocketclientisabletopublishmessagestotheserverviabidirectionalWebSocketprotocol.Seehttp-websocketfordetails.

JSONPathsupport

CitrusisabletoworkwithXpathexpressionsinseveralfieldswithinthetestingdomain(overwriteelements,ignoreelements,extractvaluesfrompayloads).NowthissupportofmanipulatingmessagepayloadsviaexpressionsisextendedwithJSONPath.SimilartoXpaththeJSONPathexpressionstatementsenableyoutofindelementsandvalues

CitrusReferenceGuide

543Changes2.3

Page 544: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

withinamessagepayload.NotverysurprisingtheJSONPathexpressionsworkwithJsonmessagepayloads.Withthenewreleaseyoucanoverwrite,ignoreandmanipulateJsonelementsusingJSONPathexpressions.Seejson-pathfordetails.

Customizemessagevalidators

TheframeworkoffersseveralmessagevalidatorimplementationsfordifferentmessageformatslikeXML,JSON,plaintextandsoon.InadditiontothatCitrushasasetofGroovyscriptmessagevalidators.AllthesevalidatorimplementationsareactivebydefaultsoyouareabletovalidateincomingmessagesaccordinglyinCitrus.Nowwiththisreleaseweaddedamorecomfortablewayofchangingtheframeworkvalidationfunctionality,particularwhenaddingnewcustomizedmessagevalidatorimplementations.Seevalidationfordetails.

Libraryupgrades

WehaveupgradedtheversionsofthemajordependencylibrariesofCitrus.ThisincludesTestNG,JUnit,SpringFramework,SpringWS,SpringIntegration,ApacheCamel,Arquillian,Jettyandmore.SoCitrusisnowworkingwithup-to-dateversionsofthewholemessagingandmiddlewareintegrationgang.

UpgradefromCitrus2.2

AlongwithnewfeaturesandimprovementswerefactoredandchangedsomepartsofCitrussoyoumighthavetosetthingsstraightwhenupgradingto2.3.Seethefollowinglistofthingsthatmightbebroughtuptoyou:

@CitrusTestannotation:Wehavemovedthe@CitrusTestannotationtoamorecommonpackage.Theoldpackagewascom.consol.citrus.dsl.annotations.CitrusTest.Thenewpackageiscom.consol.citrus.annotations.CitrusTest.SoyouhavetochangetheJavaimportstatementsinyourTestclasseswhenupgrading.

TestResult:WechangedtheTestResultinstantiationwhengeneratingthetestreports.TheTestResultclassnowworkswithstaticinstantiationmethodsforsuccess,skippedandfailedtests.Thisonlyaffectsyourcodewhenyouhavecreatedcustomtestreporters.

CitrusReferenceGuide

544Changes2.3

Page 545: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

CitrusTestBuilderdeprecation:AmajorrefactoringwasdoneintheTestBuilderJavaDSLcode.com.consol.citrus.dsl.TestBuilderandallitssubclassesweremarkedasdeprecatedandwilldisappearinnextversions.Soinsteadwenowsupportcom.consol.citrus.dsl.design.TestDesignerwhichbasicallyoffersthesamefunctionalityasformerTestBuilder.InadditionthatrefactoringbroughtanewwayofexecutingtheJavaDSLtestcases.Insteadofbuildingthewholetestcasebeforeexecutionisdoneasawholeyoucannowusethecom.consol.citrus.dsl.runner.TestRunnerimplementationinordertoexecuteeachtestactionintheJavaDSLimmediately.ThisisamoreJavalikewayofwritingCitrustestcasesasyoucanmixCitrustestactionexecutionwithnormalJavastatementsasusual.Readmoreaboutthenewapproachintestcase

Bugfixes

Bugsarepartofoursoftwaredevelopersworldandfixingthemispartofyourdailybusiness,too.FindingandsolvingissuesmakesCitrusbettereveryday.ForadetailedlistingofallbugfixespleaserefertothecompletechangeslogofeachreleaseinJIRA(http://www.citrusframework.org/changes-report.html).

CitrusReferenceGuide

545Changes2.3

Page 546: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ChangesinCitrus2.2Citrus2.2isareleasemostlyaddingnewfeaturesaswellasimprovementstogivenCitrusfeatures.Bugfixesofcoursearealsopartofthepackage.Seethefollowingoverviewonwhathaschanged.

Arquilliansupport

ArquillianisawellknownintegrationtestframeworkthatcomeswithagreatfeaturesetwhenitcomestoJavaEEtestinginsideofafullqualifiedapplicationserver.WithArquiliianyoucandeployyourJavaEEservicesinarealapplicationserverofyourchoiceandexecutethetestsinsidetheapplicationserverboundaries.ThismakesitveryeasytotestyourJavaEEservicesinscopewithproperJNDIresourceallocationandotherresourcesprovidedbytheapplicationserver.CitrusisabletoconnectwiththeArquilliantestcase.SpeakinginmoredetailyourArquilliantestisabletouseaCitrusextensioninordertousetheCitrusfeaturesetinsidetheArquillianboundaries.Seearquillianfordetails.

JUnitsupport

CitrussupportsbothmajorplayersinunittestingTestNGandJUnit.UnfortunatelywedidnotofferthesamefeaturesupportforJUnitasitwasdoneforTestNG.NowwithCitrus2.2weimprovedtheJUnitsupportinCitrussoyouareabletouseallfeatureswithbothframeworks.Thisisespeciallyrelatedtousingthe@CitrusTestand@CitrusXmlTestmethodannotationsintestclasses.Seerun-junithowitworks.

Start/Stopserveraction

CitruswasmissingadedicatedtestactiontostartandstopCitrusservercomponentsattetruntime.Withthenewlyaddedtestactionsyouareabletostartandstopservercomponentsasyoulikewithinyourtestcase.Seeactions-manage-serverwithadetaileddescription.

CitrusAnttasks

CitrusReferenceGuide

546Changes2.2

Page 547: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

WediscontinuetosupporttheCitrusAnttasks.TheAnttaskswerenotverystableanlackedfullfeaturesupportwhenexecutingtestcaseswithJUnitinApacheAnt.InsteadweaddedabriefdescriptiononhowtoexecuteCitrustestswiththewelldocumentedandstabledefaultJUnitandTestNGanttasks.Seesetup-using-anthowitworks.

Bugfixes

Bugsarepartofoursoftwaredevelopersworldandfixingthemispartofyourdailybusiness,too.FindingandsolvingissuesmakesCitrusbettereveryday.ForadetailedlistingofallbugfixespleaserefertothecompletechangeslogofeachreleaseinJIRA(http://www.citrusframework.org/changes-report.html).

CitrusReferenceGuide

547Changes2.2

Page 548: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ChangesinCitrus2.1Citrus2.1addssomeenhancementstotheCitrusfeaturesetaswellasbugfixesandimprovements.Seethefollowingoverviewonwhathaschanged.

SOAPMTOMsupport

SOAPMTOMstandsforMessageTransmissionOptimizationMechanismwhichallowsyoutosendandreceivelargeSOAPattachmentcontentsstreamedwithoptimizedresourceallocationonserverandclient.Manythankstocommunitycontributions(github/stonator)thatmadethishappenwithCitrusSOAPclientandserver.AsauseryoucanshoosetosendandreceiveSOAPattachmentswithMTOMoptimization.Seesoap-attachment-mtomfordetails.

SOAPenvelopehandling

InitsdefaultbehaviorCitruswillremovetheSOAPenvelopeforincomingSOAPrequestsjustprovidingtheSOAPbodyasmessagepayload.Thisismorestraightforwardinatestcasetoperformfurthervalidationsteps.HoweveritmightbemandatorytoseethewholeSOAPenvelopeinsidethetestcaseforspecialvalidation.AsauseryoucannowchoosehowtohandleincomingSOAPenvelopebydefinigthekeep-soap-envelopesettingontheCitrusSOAPservercomponents.Seesoap-keep-envelopefordetails.

SOAP1.2messagefactory

TheCitrusSOAPservercomponentwasmissingasettingfortheSOAPmessagefactorytouse.TheSOAPmessagefactoryimplementationdecideswhichSOAPversiontouse1.1or1.2.NowyoucansetthemessagefactoryontheservercomponentanddefinetheSOAPversiontouse.Seesoap-12fordetails.

TestNGdataproviderhandling

WeimprovedtheTestNGdataproviderhandlinginCitrus.NowyoucanusetheusualTestNGdataproviderannotationsinyourtestmethods.TestNGwillcalltheCitrustestcaseseveraltimeswithrespectiveparametersprovidedastestvariables.Thisreplaces

CitrusReferenceGuide

548Changes2.1

Page 549: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

theoldcitrusDataProvidermechanismthattriedtomakethingsworkinginakindofworkaround.Thenewproviderhandlingalsosupportsmultipledataprovidersinatestclass.run-testng-data-providersdescribeshowthisisworkingforyou.

Mailmessagenamespace

TheCitrusmailcomponentsenablemessageexchangeasmailclientandserver.ForvalidationpurposethecomponentsofferaXMLmailmessagerepresentation.Wehaveaddedatargetnamespacexmlns="http://www.citrusframework.org/schema/mail/message"andaXSDschemaforthisXMLmailmessagerepresentation.FromnowonyouhavetousethenamespaceaccordinglyinyourmailmessagepayloadswhensendingandreceivingmailmessagesinCitrus.SeemailhowtousethenewXMLmailmessagenamespace.

Sshmessagenamespace

WhensendingandreceivingmessagesviasshCitrusprovidesaXMLrepresentationforrequestandresponsedata.Thesesshmessagesfollowanewtargetnamespacexmlns="http://www.citrusframework.org/schema/ssh/message"andaXSDschema.ThismeansyouhavetousethenamespaceaccordinglyinyoursshmessagepayloadswhensendingandreceivingsshmessagesinCitrus.Seesshforfurtherdetails.

CitrusReferenceGuide

549Changes2.1

Page 550: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ChangesinCitrus2.0Citrus2.0isamajorversionupgradeandthereforebigthingsshouldbehappening.InthefollowingsectionsweshortlydescribetheCitrusevolution.WewantyoutogetaquickoverviewofwhathashappenedandallthenewthingsinCitrus.Sohopefullyyoucanspotyourfavoritenewfeature.

Refactoring

InCitrus1.4webegantorefactortheconfigurationcomponentsinCitrus.ThisrefactoringwasfinalizedinCitrus2.0whichmeansthatalldeprecatedclassesandapiarenolongersupported.Theclasseswereremovedsoyougetcompilationerrorswhenusingthoseoldstuff.Ifyoustillusetheoldconfigurationseethishttp://citrusframework.org/migration-sheet.htmlinordertolearnhowtoupgradetothenewconfiguration.Itisworthtodoso!Inadditiontothatwedidrefactoringinfollowingfields:

ReplymessagecorrelationInsynchronouscommunicationscenariosCitrusoptionallycorrelatedmessagesacrosssendandreceivetestactions.Indefaultsettingthemessagecorrelationwasdisabled.With2.0releasewechangedthisbehaviortotheopposite.Nowmessagecorrelationisdonebydefaultwithadefaultcorrelationalgorithm.SoincaseyouusedtheDefaultReplyMessageCorrelatorinCitrusbeforeyouwillnothavetodosoinfutureasthisisdonebydefault.Themessagecorrelationgivesusmorerobusttestsespeciallywhenexecutingtestsinparallel.Inthetestcaseyoudonothavetodoanythingforpropermessagecorrelation.

CitrusmessageAPIWehaverefactoredtheCitrusmessageAPItousecustommessageobjectsinendpoints,consumersandproducers.Thishasnoaffectonyourtestsorconfigurationunlessyouhavewrittenendpointextensionsorcustomendpointsonyourown.Youmighthavetorefectoryourcodeaccordingly.HavealookattheCitrusendpointimplementationsinordertoseehowthenewmessageAPIworksforyou.

SleeptimeinmillisecondsThisissomethingthatwedefinitelycarryaroundsincethebeginningofCitrus.Thetimevaluesinsleeptestactionweredoneinseconds,whichisinconvenientwhenusingtimeperiodsbelowonesecondornonnatural

CitrusReferenceGuide

550Changes2.0

Page 551: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

numbers.Nowyoucanchoosetousemillisecondswhichismorelikelyhowyoushouldconfiguretimeperiodsanyway.Seeactions-sleepfordetails

AutosleeptimeinmillisecondsWeusedsecondswhenusingautosleepinrepeatonerrorcontainer.Thisledtothefactthatwewerenotabletosleeptimeperiodsbelowonesecond.Alsoitwasnotpossibletospecifynonnaturalnumberssuchas1.5secondsautosleeptime.Wechangedtomillisecondswhichismorelikelyhowyouareusedtoconfiguretimeperiodsanyway.Seecontainers-repeat-onerrorfordetails

Messagehandlervs.endpointadapterInpreviousreleasespriorto1.4wehadmessagehandlersonserversidethatwereabletoforwardincomingrequeststomessagechannelsorjmsdestinations.Theoldmessagehandlerimplementationswereremovedin2.0.Insteadyoushouldusetheendpoint-adapterimplementations.Seeendpoint-adapterhowthatworks.

XMLendpointreferenceattributeInaXMLtestcaseyoureferencethemessageendpointinthesendandreceiveactionswithaspecialattributecalledwith.Thisattributeisnolongersupportedandwasremoved.InsteadyoushouldusetheendpointattributewhichwasintroducedinCitrus1.4andhastheexactsamefunctionality.

Removedcitrus-adaptermoduleTheMavenmodulecitrus-adapterwasremoved.ClassesandAPImovedtocitrus-coremodule.ForendpointadaptersdousethenewconfigurationcomponentsthatwereintroducedinCitrus1.4.Seeendpoint-adapterfordetails.

WebServiceEndpointclassrenamedIntermsofpackagerefactoringthecom.consol.citrus.ws.WebServiceEndpointwasrenamedtocom.consol.citrus.ws.server.WebServiceEndpoint

Springframework4.x

IntermsofupgradingtheCitrusAPIdependenciesweintroducedSpring4.xversions.ThisincludesthecoreSpringframeworklibrariesaswellastheSpringIntegrationandSpringWebServiceprojectartifacts.SowiththemajorversionupgradelotsofAPIchangeswerealsodoneinCitruscodeinordertomeetthenewSpring4.xAPI.SowerecommendforyoutoalsouseSpring4.xversioninyourCitrusprojects.

FTPsupport

CitrusReferenceGuide

551Changes2.0

Page 552: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

NewmemberoftheCitrusfamilydealswithFTPconnectivity.Thenewcitrus-ftpmoduleprovidesaneatftpserverandclientimplementationsoyoucansendandreceivemessagesvieFTPmessagetransport.ftpdescribesthenewfunctionalityindetail.

Functionswithtestcontextaccess

Functionsarenowabletoaccessthetestcontext.Thisenablesyoutoaccessalltestvariablesandothercentraltestrelatedcomponentsinafunctionimplementation.ThereforethefunctionJavainterfacehasnowanadditionaltestcontextparameter.Refactoryourcustomwrittenfunctionsaccordinglytomeetthenewinterfacerules.Seehttp://www.citrusframework.org/tutorials-functions.htmlfordetails.

Validationmatcherwithtestcontextaccess

Justlikefunctionsnowvalidationmatchersareabletoaccessthetestcontext.Thisenablesyoutoaccessalltestvariablesandothercentraltestrelatedcomponentsinavalidationmatcherimplementation.ThevalidationmatcherJavainterfacehaschangedaccordinglywithanadditionaltestcontextparameter.Refactoryourcustomwrittenmatcherimplementationaccordinglytomeetthenewinterfacerules.

Messagelistenerwithtestcontextaccess

Messagelistenersdonowalsohaveaccesstothetestcontext.Thisismorepowerfulasyoucanaccesstestvariablesandothercentralcomponentswithinthetestcontext.

SOAPoverJMS

SOAPoverJMSwassupportedinCitrusfromtheverybeginning.UnfortunatelyyouhadtoalwaysspecifythewholeSOAPenvelopeinyourtestcase.SOAPenvelopehandlingisnowdoneautomaticallybyCitruswhenusingthenewSoapJmsMessageConverter.TheconvertertakescareonconstructingaproperSOAPenvelopemessage.Seejms-soapfordetails.

MultipleSOAPattachments

WhensendingandreceivingSOAPmessageswithCitrusasclientorserveryoucanaddonetomanyattachmentstothemessage.Beforeitwasonlypossibletohaveonesingleattachmentinamessage.NowyouhavenolimitsindefiningSOAPattachments.

CitrusReferenceGuide

552Changes2.0

Page 553: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Seesoap-webservicesfordetails.

MultipleSOAPXMLheaderfragments

TheSOAPheadercanholdmultipleXMLheaderfragmentswithdifferentnamespacesandcontent.WithCitrus2.0youareabletoconstructsuchaSOAPmessagewithmultipleheadercontents.Seesoap-webservicesfordetails.

Createvariablevalidationmatcher

Anewvalidationmatcherimplementationisabletocreateanewvariableonthefly.Theactualfieldnameisusedasvariablenameandtheelementvalueasvariablevalue.Thevariablenamecanslobecustomizedwithoptionalvalidationmatcherparameter.ThisisagreatalternativetotheXPathexpressionevaluatingvariableextraction.AlsoveryhandsometousethisvalidationmatcherinJsonmessagepayloads.Seevalidation-matcher-variablefordetails.

Newconfigurationcomponents

AmajorpartoftheCitrusconfigurationisdoneinaSpringbeanapplicationcontext.CentralCitruscomponentsandfeaturesareaddedasSpringbeanstotheapplicationcontext.NowwithCitrus2.0wehaveaddedspecialconfigurationcomponentsforalmostallfeatures.ThismeansthatyoucaneasilyaddconfigurationusingthenewXMLschemacomponents.Seewhichcomponentsareavailable:

FunctionlibraryCustomfunctionlibrarieswithcustomfunctionimplementationsarenowconfiguredwiththefunction-libraryXMLschemacomponentsintheSpringapplicationcontextconfiguration.Seefunctionsfordetails.

ValidationmatcherlibraryCustomvalidationmatcherimplementationsarenowconfiguredwiththevalidation-matcher-libraryXMLschemacomponentsintheSpringapplicationcontextconfiguration.Seevalidation-matchersfordetails.

DatadictionaryDatadictionariesapplytoallmessagessendandreceivedintestcases.Youcandefinemultipledictionariesusingthedata-dictionaryXMLschemacomponentsintheSpringapplicationcontextconfiguration.Seedata-dictionaryfordetails.

CitrusReferenceGuide

553Changes2.0

Page 554: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

NamespacecontextConfigurationofaglobalnamespacecontextisnecessaryforXMLmessagepayloadsandXPathexpressionsusedinthetestcases.Thenamespace-contextXMLschemacomponentisusedintheSpringapplicationcontextconfigurationandsimplifiestheconfiguration.Seexpathfordetails.

Before/aftersuitecomponents

Whenexecutingtestactionsbeforetheactualtestrunyoucanusethesequencebeforesuitecomponents.WehaveimprovedthesecomponentstouseaspecialXMLschema.Thisenableseasyconfigurationofbothbeforeandaftersuiteactions.Inadditiontothatyoucanbindthesuiteactionstospecialpackages,testnamesorsuitenames.Soyoucannowhavemorethanonesequencebeforesuiteatthesametime.Accordingtotheenvironmentsettingsthebeforesuiteactionsareexecutedorleftout.Lastnotleastwehavedonethesameimprovementtothebeforetestactionsandwehaveintroducedaaftertestsequencecomponentforexecutionaftereachtest.Seehowthisisdoneintestsuite.

CitrusJMSmodule

JMSsupporthasbeenamajorpartofCitrusfromtheverybeginning.UptonowtheJMSfeatureswerelocatedincitrus-coreMavenmodule.WithCitrus2.0weintroducedaseparatecitrus-jmsMavenmodule.ThismeansthatyoumighthavetoaddproperMavendependencyofthisnewmoduleinyourexistingprojectwhenusingJMS.Seehowthisisdoneinjms.

CitrusReferenceGuide

554Changes2.0

Page 555: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ChangesinCitrus1.4.x

Refactoring

ItwastimeforustodosomecoderefactoringinCitrus.ManyusersstruggledwiththeconfigurationoftheCitruscomponentsandprojectsetupwastooverboseinsomeareas.ThisiswhywetriedtoimprovethingswithworkingoverthebasicconceptsandcomponentsinCitrus.

TheoutcomeisanewCitrus1.4whichhasnewconfigurationcomponentsforsendingandreceivingmessages.AlsotheclientandservercomponentsforHTTPandSOAPhavechangedintermsofsimplification.Unfortunatelyrefactoringcomesalongwithcodedeprecation.Thisiswhyyouhavetoalsochangeyourprojectcodeandconfigurationinthefuture.ThisisespeciallywhenyouhavemadecodeadjustmentsandextensionstotheCitrusAPI.

ThegoodnewsnowisthatwithCitrus1.4botholdandnewconfigurationworksfine,soyoudonothavetochangeyourexistingprojectconfigurationwhencomingfromCitrus1.3.xandearlierversions.ButthereisalotofcodemarkedasdeprecatedinCitrus1.4.HavealookatwhathasbeenmarkedasdeprecatedandupdateyourcodetousethenewAPI.

WehavesetupamigrationsheetforuserscomingfromCitrus1.3.xandearlierversionsinordertofindaquickoverviewofwhathaschangedandhowtousethenewconfigurationcomponents:http://citrusframework.org/migration-sheet.html

Datadictionaries

Datadictionariesdefinedynamicplaceholdersformessagepayloadelementvaluesingeneralmanner.Intermsofsettingthesamemessageelementacrossalltestcasesandalltestactionsthedictionaryprovidesaneasykey-valueapproach.

WhendealingwithanykindofmessagepayloadCitruswillaskthedatadictionaryforpossibletranslationofthemessageelementscontained.ThedictionarykeysdomatchtoaspecificmessageelementdefinedbyXPathexpressionordocumentpathexpressionforinstance.TherespectivevalueisthensetonallmessagesinCitrus(inboundandoutbound).

CitrusReferenceGuide

555Changes1.4

Page 556: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

DictionariesdoapplytoXMLorJSONmessagedataandcanbedefinedinglobalorspecificscope.Findoutmoredetailedinformationaboutthistopicindata-dictionary

Mailadapter

Withthenewmailadapteryouareabletobothsendandreceivemailmessageswithinatestcase.ThenewCitrusmailclientproducesamailmimepartmessagewithusualmailheadersandatextbodypart.Optionalattachmentpartsaresupported,too.

OntheserversideCitrusprovidesaSMTPservertoacceptclientmailmessages.Theincomingmailmessagescanhavemultipletextpartsandattachmentparts.AsusualyoucanvalidatetheincomingmailmessagesregardingheadersandpayloadwiththewellknownvalidationcapabilitiesinCitrus.

Readmoreaboutthenewmailmoduleinmail

Endpointadapter

EndpointadaptershelptocustomizethebehaviorofaCitrusserversuchasHTTPorSOAPwebservers.Theendpointadapterisresponsibleofcreatinganendpointthatrespondstoinboundrequests.YoucancustomizethebehaviorsotheCitrusserverhandlesincomingrequestsasyoulike.

BydefaulttheCitrusserverusesachannelendpointadaptersoincomingmessagesgetforwardedtoaninmemorymessagechannel.Thereareseveralotherimplementationsavailableasendpointadapter.Readmoreaboutthatinendpoint-adapter

Globalvariablescomponent

WeaddedaglobalvariablesXMLconfigurationcomponentformorecomfortableusageinbasicSpringapplicationcontextconfiguration.ThecomponentisabletocreatenewglobalvariablesthatarevalidacrossallCitrustestcases.Thiscanalsobedonebyloadingapropertyfilefromanexternalfileresource.Findouthowtousitintestcase-global-variables

Jsontextvalidatormode

TheJsontextvalidatorisnowabletooperateintwodifferentmodes.Thestrictmodeisthedefaultmodeandvalidationincludesalsoastrictcheckonallsub-objectsandJSONarrayelements.Soifthereisanobjectmissingthevalidationwillfailimmediately.

CitrusReferenceGuide

556Changes1.4

Page 557: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

SometimesitmaybeaccuratetoonlyvalidateasubsetofallJSONobjectsinthedatastructure.Thereforethenon-strictmodedoesnotcheckonobjectattributecounts.Seemoredescriptioninvalidation-json

HTTPRESTspecificJavaDSLoptions

WhensendingandreceivingHTTPmessagesonRESTAPIsyoucannowuseinterfacespecificoptionsintheJavaDSL.Thisreferstorequesturi,contextpath,queryparametersandHTTPstatuscodesforinstance.WiththisenhancementyouarenowmorecomfortableinhandlingRESTAPIcallsinCitrus.Findouthowtousitinhttp

SOAPHTTPvalidation

WhilereceivingSOAPmessagesoverHTTPwearenowabletoalsoverifytheusedHTTPuri,context-pathandqueryparameters.YoucanexpectclientstousethosevaluesinyourreceiveactionasyouwoulddoinnormalHTTPcommunicationwithinCitrus.ThiscompletestheHTTPservervalidationwhenusingSOAPoverHTTP.Readmoreaboutitinsoap-webservices

ApacheCamelintegration

ApacheCamelisagreatenterpriseintegrationplatformthatimplementstheenterpriseintegrationpatternsforbuildingpowerfulmediationandroutingrulesformessagebasedintegrationapplications.WiththenewsupportforcamelendpointsinCitrusyoucaninteractwithApacheCamelcomponentsforsendingandreceivingmessages.ApacheCameloffersafinesupportfordifferentmessagetransportsthatnowcanbeusedinCitrusalso.InadditiontothatyoucanputyourCamelapplicationtothetestwithloadingoftheApacheCamelcontextwithallyourroutedefinitions.Citrusisabletointeractwiththeseroutesinasynchronousandsynchronouscommunicationscenarios.Readaboutitincamel.

Vert.xintegration

Vert.xisaverypowerfulapplicationplatformthatprovidesscalablemessagingforseveralmessagetransportssuchasHTTP,WebSockets,TCPandmore.Vert.xalsohasadistributedeventbusthatconnectsmultipleVert.xinstancesacrossthenetwork.WithCitrus1.4theVert.xplatformisintegratedwithCitruseventbusendpoints.Soyou

CitrusReferenceGuide

557Changes1.4

Page 558: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

canparticipateincommunicatingtotheVert.xeventbusfromCitrustestcase.ThisenablesyoutoaddautomatedintegrationteststotheVert.xplatform.Readaboutthatinvertx.

Dynamicendpointcomponents

EndpointsrepresentthebasecomponentinCitrusforsendingandreceivingmessages.TheendpointusuallyisdefinedinsidetheCitrusSpringapplicationcontextasSpringbeancomponent.Nowitisalsopossibletocreatedynamicendpointdefinitionsattestruntime.ThiscomesinveryhandywhenyoujustwanttosendorreceiveamessagewithCitrusasis.Youdonotneedtoaddthecompleteendpointconfigurationbutonlyuseaspecialendpointuripattern.Citruswillcreatetheendpointatruntimeautomatically.Learnhowtousethedynamicendpointpatterninendpoint-components.

CitrusReferenceGuide

558Changes1.4

Page 559: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ChangesinCitrus1.3.x

@CitrusTestand@CitrusXmlTestannotations

WiththenewJavaDSLcapabilitiesCitruscreatednewwaysofexecutingtestcaseswithinaTestNGorJUnittestclass.Nowweevenimprovedtheusageherewithtwonewannotations@CitrusTestandCitrusXmlTest.Theintegrationintotheunittestclasshasneverbeeneasierforyou.

ThenewCitrusannotationsgodirectlytoyourunittestmethods.WiththisenhancementyoucanhavemultipleCitrustestcasesinonesingleJavaclassandtheCitrustestsnowareabletocoexistwithotherunittestmethods.YoucanevenmixJavaDSLandXMLCitrustestcasesinasingleJavaclass.

TheXMLCitrustestscanbegroupedtoasingleJavaclasswithmultipleXMLfilesloadedduringexecution.ThereisevenapackagescanforallCitrusXMLfileswithinadirectorystructuresoyoudonothavetocreateaJavaclassforeachtestcaseanymore.

Wehavechangedthedocumentationinthisguidesoyoucanseehowtousethenewannotations.Fordetailedoverviewseerun-config-testng.AlsoseeourCitrusblogwherewecontinuouslydescribethemanypossibilitiesthatyouhavewiththenewannotations.

@CitrusParametersannotation

CitrusisabletousethefabulousTestNGdataprovidercapabilitiesinordertoexecuteatestcaseseveraltimeswithdifferentdataprovidedformexternalresources.Thenew@CitrusParametersannotationhelpstosetparameternameswhichareusedastestvariablenamesinthetestcase.

Schemarepositoryconfigurationcomponents

Definingschemarepositoriesandschemas(xsd,wsdl)iscommonuseinCitrus.WehaveaddedXMLbeandefinitionparserssodefiningthosecomponentsislessverbose.YoucanusetheCitruscitrus:schema-repositoryandcitrus:schemacomponentsinyourSpringapplicationcontextconfiguration.Thecomponentsdoreceiveseveralattributesforfurtherconfiguration.XSD,WSDLandschemacollectionsaresupportedhere.

CitrusReferenceGuide

559Changes1.3

Page 560: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Checkoutxsd-validationforexampleshowtousethenewconfigurationcomponents.

Changedatefunction

WehaveaddedanewCitrusfunctioncitrus:changeDate()thatisavailableforyoubydefault.Thefunctionchangesagivendatevalueaddingorremovingadatetimeoffset(e.g.year,month,day,hour,minute,second).Soyoucanmanipulateeachdatevaluealsothoseofdynamicnaturecomingwithsomemessage.

Seefunctions-changedateforexamplesanddetailedsyntaxusageofthisfunction.

Weekdayvalidationmatcher

Thenewweekdayvalidationmatcheralsoworksondatevalues.Thematcherchecksthatagivendatevalueevaluatestoaexpecteddayoftheweek.Sotheusercancheckthatadatefieldisalwaysasaturdayforinstance.Thisisveryhelpfulwhencheckingthatagivendatevalueisnotaworkingdayforexample.

Seevalidation-matcher-weekdayforsomemoredetaileddescriptionofthematcher'scapabilities.

JavaDSL

Citrususers,inparticularthosewithdevelopmentexperience,dooftentellmeaboutthenastyXMLcodetheyhavetodealwithforwritingCitrustestdefinitions.DeveloperswanttowriteJavacoderatherthanXML.AlthoughIpersonallydoliketheCitrusXMLtestsyntaxwehaveintroducedaJavaDSLlanguageforwritingCitrustestswithJavaonly.

WehaveintroducedtheJavaDSLtoallmajortestactionfeaturesinCitrussoyoucanswitchwithouthavingtoworryaboutloosingfunctionality.DetailscanbeseeninthetestactionsectionwhereweaddedJavaDSLexamplesalmosteverywhere(actions).ThebasicJavaDSLsetupisdescribedintestcase.

XHTMLmessagevalidation

MessagevalidationforHtmlcodewasnotreallycomfortableasHtmldoesnotconfirmtobewellformedandvalidXMLsyntax.XHTMLtriestoclosethisgapbyautomaticallyresolvingallHtmlspecificXMLsyntaxruleviolations.WithCitrus1.3weintroducedaXHTMLmessagevalidatorwhichdoesthemagicforconvertingHtmlcodetoproper

CitrusReferenceGuide

560Changes1.3

Page 561: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

wellformedandvalidXML.InatestcaseyoucanthenusethefullXMLvalidationpowerinCitrusinordertovalidateincomingHtmlmessages.Sectionvalidation-xhtmldealswiththenewvalidationcapabilitiesforHtml.

MultipleSOAPfaultdetailsupport

SOAPfaultmessagescanholdmanySOAPfaultdetailelements.CitruswasabletohandleasingleSOAPfaultdetailonsendingandreceivingtestactionsfromtheverybeginningbutmultipleSOAPfaultdetailelementswerenotsupported.FortunatelythingsaregettingbetterandyoucansendandreceiveasmanyfaultdetailelementsasyoulikeinCitrus1.3.ForeachSOAPfaultdetailyoucanspecifyindividualvalidationrulesandexpectations.Seesoap-faultsfordetaileddescription.

Jettyserversecurityhandler

WithourJettyservercomponentyoucansetupHttpmockserversveryeasy.TheserverisautomaticallyconfiguredtoacceptHttpclientconnectionsandtoloadaSpringapplicationcontextonstartup.Nowyoucanalsosetsomemoredetailsonthisautomaticserverconfiguration(e.g.servercontextpath,servletnamesorservletmappings).Inadditiontothatyoucanaccessthesecuritycontextofthewebcontainer.Thisenablesyoutosetupsecurityconstraintssuchasbasicauthenticationonserverresources.Clientsarethenforcedtoauthenticateproperlywhenaccessingtheserver.Unauthorizeduserswillget401accessdeniederrorsimmediately.Seehttp-basic-auth-serverfordetails.OfcoursethisalsoappliestoourSOAPWebServiceJettyservercomponents(soap-basic-auth-server).

Testactors

Weintroducedanewconceptoftestactorsforsendingandreceivingtestactions.Thisenablesyoutolinkatestactor(e.g.interfacepartnerapplication,backendapplication)toatestactioninyourtest.Followingfromthatyoucanenable/disabletestactorsandalllinkedtestactionsveryeasy.ThisenablesustoreuseCitrustestcasesinend-to-endtestscenarioswherenotallinterfacepartnersgetsimulatedbyCitrus.Ifyouliketoreadmoreaboutthisconceptfollowthedetailedinstructionintest-actors.

SimulateHttperrorcodeswithSOAP

CitrusReferenceGuide

561Changes1.3

Page 562: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

CitrusprovidesSOAPWebServicesserversimulationwithclientsconnectingtotheserversendingSOAPrequests.AsaserverCitrusisnowabletosimulateHttperrorcodeslike404Notfoundand500Internalservererror.BeforethattheCitrusSOAPserverhadtoalwaysrespondwithaproperSOAPresponseorSOAPfault.Seesoap-http-errorsfordetails.

SSHserverandclient

TheCitrusfamilyhasraisedanewmemberinaddingSSHconnectivity.WiththenewSSHmoduleyouareabletoprovideafullstackSSHserver.TheSSHserveracceptsclientconnectionsandyouasatestercansimulateanySSHserverfunctionalitywithpropervalidationasitisknowntoCitrusSOAPandHTTPmodules.InadditiontothatyoucanalsousetheCitrusSSHclientinordertoconnecttoanexternalSSHserver.YoucanexecuteSSHcommandsontheSSHserverandvalidatetherespectiveresponsedata.Thefulldescriptionisprovidedinssh.

ANTruntestaction

WiththisnewtestactionyoucancallANTbuildsfromyourtestcase.TheactionexecutesoneormoreANTbuildtargetsonabuild.xmlfile.YoucanspecifybuildpropertiesthatgetpassedtotheANTbuildandyoucanaddacustombuildlistener.IncasetheANTbuildrunfailsthetestfailsaccordinglywiththebuildexception.Seeactions-antrunfordetails.

Pollingintervalforreplyhandlers

WithsynchronouscommunicationinCitruswealwayshaveacombinationofasynchronousmessagesenderandareplyhandlercomponent.Thesetwoperformahandshakewhenpassingsynchronousreplymessagestothetestforfurtherprocessingsuchasmessagevalidation.Whilethesenderiswaitingforthesynchronousresponsetoarrivethereplyhandlerpollsforthereplymessage.Thispollingforreplymessageswasdoneinastaticwaywhichoftenledtotimedelaysaccordingtolongpollingintervals.NowwithCitrus1.3youcansetthepolling-intervalforthereplyhandlerasyoulike.ThissettingisvalidforallreplyhandlercomponentsinCitrus(citrus-jms,citrus-http,citrus-ws,citrus-channel,citrus-shh,andsoon).

Upgradingfromversion1.2

CitrusReferenceGuide

562Changes1.3

Page 563: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

IfyouarecomingfromCitrus1.2youmayhavetolookatthefollowingpointsinordertohaveasmoothupgradetothenewreleaseversion.

JettyversionupgradeWeareusingJettyalotforstartingHttpservermockswithinCitrus.InordertostayuptodateweupgradedtoJetty8.1.7versionwiththisCitrusrelease.ThisimpliesthatpackagenamesdidchangeforJettyAPI.IngeneralthereisnoconflictforyouasaCitrususer,butyoumaywanttoadjustyourloggingconfigurationaccordingtonewJettypackages.Jettypackagenamesdidchangefromord.mortbaytoorg.eclipse.jetty.

SpringversionupgradeStayinguptodatewiththeversionsof3rdlibrarydependenciesisquiteimportantforus.Soweupgradeourdependenciestonewerversionswitheachrelease.Aswedidonlyupgrademinorversionsthereisnosignificantchangeorproblemstobeexpected.HoweveryoumaytakecareonversionsandreleasechangesintheSpringworldfordetailsandmigration.

TIBCOmoduleWedecidedtoputtheTIBCOmoduleseparatelyasitisaveryspecialconnectivityadapterforTIBCOsoftwareonly.SoyouwillnotfindtheTIBCOmodulewithintheCitrusdistributionanymore.WewillmaintainaTIBCOconnectivityadapterseparatelyinthefuture.

CitrusReferenceGuide

563Changes1.3

Page 564: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

ChangesinCitrus1.2

Springversionupdate

WehavesomemajorversionupgradesinourSpringdependencies.WearenowusingSpring3.1.1,SpringIntegration2.1.2andSpringWS2.1.0.Thisupgradewasoverdueforsometimeandisdefinitelyworthit.WiththeseupgradeswehadtoapplysomechangesinourAPI,too.ThisisbecauseweareusingtheSpringclassesalotinourcode.Seetheupgradeguideinthischapterforallsignificantchangesthatmightaffectyourproject.

Newgroovyfeatures

CitrusextendedthepossibilitiestoworkwithscriptlanguageslikeGroovy.YoucanuseGroovy'sMarkupBuildertocreateXMLmessagepayloads.YourGroovycodegoesrightintothetestcaseorcomesfromexternalfile.WithMarkupBuilderyoudonotneedtocareaboutXMLmessagesyntaxandoverhead.Justfocusonthepuremessagecontent.Youcanreadthedetailsingroovy-markupbuilder.

FurtherGroovyfeaturegoestothevalidationcapabilities.InsteadofworkingwithXMLDOMtreecomparisonandXPathexpressionvalidationyoucanuseGroovyXMLSlurper.ThisisveryusefulforthoseofyouwhoneedtodocomplexmessagevalidationanddonotliketheXML/XPathsyntaxatall.WithXMLSlurperyoucanaccesstheXMLDOMtreevianamedclosureoperationswhichfeelsgreat.ThisespeciallycomesinhandyforcomplexgenericXMLstructuresasyoucansearchforelements,sortelementlistandusethepowerfulcontainsoperation.Thisisalldescribedingroovy-xmlslurper.

SomeotherGroovysupportextensioncomesinSQLresultsetvalidation(actions-database-groovy).WhenreadingdatafromthedatabasesomeoneisabletovalidationtheresultingdatarowsetwithGroovyscript.ThescriptcodeeasilyaccessestherowsandcolumnswithGroovy'sout-of-the-boxlistandmaphandling.Thisaddsverypowerfulvalidationtomulti-rowdatasetsfromthedatabase.

SQLmulti-lineresultsetvalidation

CitrusReferenceGuide

564Changes1.2

Page 565: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

InthisnewCitrusversionthetestercanvalidateSQLQueryresultsthathavemultiplerows.InthepastCitruscouldonlyhandleasinglerowintheresultset.Nowthisnewreleasebringslightintothedark.SeealsothenewGroovySQLresultsetvalidationwhichfitsbrilliantforcomplexmulti-rowSQLresultsetvalidation.Thedetailscanbefoundinactions-database-query

Extendedmessageformatsupport

InpreviousversionsCitruswasprimarydesignedtohandleXMLmessagepayloads.WiththisnewreleaseCitrusisalsoabletoworkwithothermessageformatssuchasJSON,CSV,PLAINTEXT.Thisappliestosendingmessagesaswellasreceivingandparticularlyvalidatingmessagepayloads.ThetestercanspecifyseveralmessagevalidatorsinCitrusfordifferentmessageformats.Accordingtotheexpectedmessageformatthepropervalidatorischosentoperformthemessagevalidation.

WehaveimplementedaJSONmessagevalidatorcapableofignoringspecificJSONentriesandhandlingJSONArrays.Wealsoprovideaplaintextmessagevalidatorwhichisverybasictobehonest.Theframeworkisreadytoreceivenewvalidatorimplementationssoyoucanaddcustomvalidatorsforyourspecificneeds.

NewXMLfeatures

XMLnamespacehandlingistediousexpeciallyifyouhavetodealwithalotofXPathexpressionsinyourtests.BeforeyouhadneedtospecifyanamespacecontextfortheXPathexpressioneverytimeyouusetheminyourtest-nowyoucanhaveacentralnamespacecontextwhichdeclaresnamespacesyouuseinyourproject.Thesenamespacesidentifiedbysomeprefixareavailablethroughoutthetestprojectwhichismuchmoremaintainableandeasytouse.Seehowitworksinxpath-namespace.

SOAPsupportimprovements

WsAddressingstandardisnowsupportedinCitrus(soap-ws-adressing).ThismeansyoucandeclarethespecificWsAddressingmessageheadersonmessagesenderlevelinordertosendmessageswithWsAddressingfeature.TheheaderisconstructedautomaticallyforallSOAPmessagesthataresentoverthemessagesender.

DynamicSOAPendpointuriresolverenablesyoutodynamicallyaddressSOAPendpointsduringatest.SometimesamessagesendermaydynamicallyhavetochangetheSOAPurlforeachcall(e.g.addressdifferentrequesturiparts).Withaendpointuri

CitrusReferenceGuide

565Changes1.2

Page 566: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

resolversetonthemessagesenderyoucanhandlethisrequirementveryeasy.Thetipfordynamicendpointresolvingwasaddedtosoap-sender

WealsosimplifiedthesynchronousSOAPHTTPcommunicationwithintestcases.InpreviousversionsyouhadtobuildcomplexparallelandsequentialcontainerconstructsinordertocontinuewithtestexecutionwhiletheSOAPmessagesenderiswaitingforthesynchronousresponsetoarrive.NowyoucansimplyforkthemessagesendingactionandcontinuewithfurthertestactionswhilesynchronousSOAPcommunicationtakesplace.Seethesoap-fork-modefordetails

SomereallysmallchangeintroducedwiththisreleaseisthefactthatCitrusnowlogsSOAPmessagesintheirpurenature.ThismeansthatyoucanseethecompleteSOAPenvelopeofmessagesintheCitruslogfiles.Thisismorethanhelpfulwhensearchingforerrorsinsideyourtestcase.

HttpandRESTfulWebServices

WehavechangedHttpcommunicationcomponentsforfullsupportofRESTfulWebServicesonclientandserverside.TheHttpclientnowusesSpring'sRESTsupportforHttprequests(GET,PUT,DELETE,POST,etc.).Theserversidehaschanged,too.TheHttpservernowprovidesRESTfulWebServicesandiscomplianttotheexistingSOAPJettyserverimplementationinCitrus.IfyouwanttoupgradeexistingprojectstothisversionyoumayhavetoadjusttheSpringapplicationcontextconfigurationtosomeextent.

Fordetailshavealookattheupgradeguide(history-upgrading)inthischapterorfinddetailedexplanationstothenewHttpcomponentsinhttp.

HTMLreporting

CitrusprovidesHTMLreportsaftereachtestrunwithdetailedinformationonthefailedtests.Youcanimmediatelyseewhichtestsfailedinexecutionandwheretheteststopped.reporting-htmlprovidesdetailsonthisnewfeature.

Validationmatchers

Thenewvalidationmatcherswillputthemessagevalidationmechanismstoanewlevel.Withvalidationmatchersyouareabletoexecutepowerfulassertionsoneachmessagecontentelement.ForinstanceyoucanusetheisNumbervalidationmatcherforchecking

CitrusReferenceGuide

566Changes1.2

Page 567: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

thatamessagevalueisofnumericnature.Weaddedseveralmatcherimplementationsthatarereadyforusageinyourtestbutyoucanalsowriteyourcustomvalidationmatchers.Havealookatvalidation-matchersfordetails.

Conditionalcontainer

Thenewconditionaltestactioncontainerenablesyoutoexecutetestactionsonlyincaseabooleanexpressionevaluatestotrue.Sothenestedtestactionsinsidethecontainermaybenotexecutedatallincaseaconditionisnotmet.Seecontainers-conditionalfordetails.

Supportformessageselectorsonmessagechannels

SpringIntegrationmessagechannelsdonotsupportmessageselectorslikeJMSqueuesdoforexample.WithCitrus1.2weimplementedasolutionforthisissuewithaspecialmessagechannelimplementation.Soyoucanusethemessageselectorfeaturealsowhenusingmessagechannels.Gotomessage-channel-selector-supportfordetails.

Newtestactions

Weintroducedsomecompletelynewtestactionsinthisreleaseforyou.Thenewactionsarelistedbelow:

Purgemessagechannelaction()

Seeactionsfordetailedinstructionshowtousethenewactions.

Newfunctions

WeintroducedsomenewdefaultCitrusfunctionsthatwilleasethetesterslife.Thisincludescommonlyusedfunctionslikeencoding/decodingbase64bindarydata,escapingXMLandgeneratingrandomJavaUUIDvalues.Thesearethenewfunctionsinthisrelease:

citrus:randomUUID()citrus:cdataSection()citrus:encodeBase64()citrus:decodeBase64()citrus:digestAuthHeader()citrus:localHostAddress()

CitrusReferenceGuide

567Changes1.2

Page 568: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

Seefunctionsfordetaildescriptionsofeachfunction.

Upgradingfromversion1.1

IfyouarecomingfromCitrus1.1finalyoumayhavetolookatthefollowingpoints.

SpringversionupdateWedidsomemajorversionupgradesonourSpringdependencies.WearenowusingSpring3.1.1,SpringIntegration2.1.2andSpringWS2.1.0.ThesenewmajorreleasesbringsomecodechangesinourCitrusAPIwhichmightaffectyourcodeandconfiguration,too.Sopleaseupdateyourconfiguration,itisdefinitelyworthit!

SpringIntegrationheaders:With2.0.xversionSpringIntegrationhasremovedtheinternalheaderprefix("springintegration_").Soinsomecasesyoumightusethoseinternalheadernamesinyourtestcasesinordertosynchronizesynchronouscommunicationwithinternalmessageids.YourtestcasewillfailaslongasyouusetheoldSpringinternalheaderprefixinthetest.Simplyremovetheheaderprefixwhereverusedandyourtestisupandrunningagain.

Messagevalidator:YouneedtospecifyatleastonemessagevalidatorintheSpringapplicationcontext.BeforethiswasinternallyastaticXMLmessagevalidator,butnowweofferdifferentvalidatorsforseveralmessageformatslikeXMLandJSON.PleaseseetheJavaAPIdoconMessageValidatorinterfaceforavailableimplementations.IfyoujustliketokeepitasitwasbeforeaddthisbeantotheSpringapplicationcontext:

<beanid="xmlMessageValidator"class="com.consol.citrus.validation.xml.DomXmlMessageValidator"

Testsuite:Wehaveeliminated/changedtheCitrustestsuitelogicbecauseitduplicatesthosetestsuitesdefinedinTestNGorJUnit.InolderversionsthetesterhadtodefineaCitrustestsuiteinSpringapplicationcontextinordertoexecutetestactionsbefore/afterthetestrun.Nowthesetasksbeforeandafterthetestrunaredecoupledfromatestsuite.YoudefinetestsuitesexclusivelyinTestNGorJUnit.Thetestactionsbefore/afterthetestrunareseparatelydefinedinSpringapplicationcontextsoyouhavetochangethisconfigurationinyourCitrusproject.

Seetestsuitefordetailsonthisconfigurationchanges.

JUnitvs.TestNG:WesupportbothfamousunittestingframeworksJUnitandTestNG.Withthisreleaseyouarefreetochooseyourpreferedone.Inthismanner

CitrusReferenceGuide

568Changes1.2

Page 569: Table of Contents - Citrus Frameworkcitrusframework.org/citrus/reference/2.7.1/pdf/citrus... · 2019-01-28 · Java 8 Citrus is now using Java 8. This is mainly because we need to

youneedtoaddeitheraJUnitdependencyoraTestNGdependencytoyourprojectonyourown.WedonothavestaticdependenciesinourMavenPOMtoneitherofthosetwo.OnoursidethesedependenciesaredeclaredoptionalsoyoufeelfreetoaddtheoneyoulikebesttoyourMavenPOM.JustaddaJUnitorTestNGdependencytoyourMavenprojectoraddtherespectivejarfiletoyourprojectifyouuseANTinstead.

CitrusReferenceGuide

569Changes1.2


Recommended