Before reading on, read my first article on the Citrus Framework.
In this second part of testing by use of the Citrus Framework i want to test a new scenario which was part of the middleware of my last customer.
Scenario
Some third party application stores messages on the Weblogic JMS queue in the middleware. My Oracle Service Bus project picks up the messages, does some transformation/enrichment/etc, and stores the data on the file share.
Storing the file on the filesystem is the trigger for starting a new process, but this will be out of scope for this article.
What we want to test is the blackbox which runs in the middleware. I want to be able to store the xml data file (fact 1), in the jms queue, and eventually read the file from filesystem (fact 2) and see if the response
matches my expected response defined in the Citrus Framework.
Requirements
See the requirements of the first article, what we need again are the inbound queues and the used connection factory. In the middleware we need a Oracle Service Bus flow.
Oracle Service Bus
The Oracle Service Bus project i want to test is a real basic one with only 2 resources.
- jms_ps – proxy service with service type ‘Any XML Service’ and jms protocol
The flow consists of only a simple route action whichs routes the incoming message of the jms queue 1 on 1 to business service which stores the content on filesystem.
- file_bs – business service which stores the file on my local file system
Citrus configuration
First we need to config src/citrus/resources/citrus-context.xml
[sourcecode language=”xml”]
[/sourcecode]
Again we use the ‘sendGreeting’ bean to send the message to the jms queue. For Citrus to be able to do his actions on the messages he needs to get the message from a MessageChannel.
When the file gets stored on filesystem the ‘inbound-channel-adapter’ will poll for the file and puts it on the ‘fileInputChannel’ messagechannel, eventually citrus will pick up the message from this channel.
Documentation of Citrus doesn’t give you any hints on how to integrate the file-protocol. Since Citrus makes use of Spring Integration we can easily adopt the file support from this framework and add it to the Citrus context file.
The following changes are needed on the citrus-context.xml file
- Addition of the integration namespaces/schemalocations
- Addition of the (file) inbound-channel-adapter
- Addition of the channel for the file
- Citrus Message channel polling on the file input channel
- Copy the Spring Integration File jar to the libs folder. I used ‘org.springframework.integration.file-1.0.3.RELEASE.jar’ from the Spring Integration framework
A few notes on the fileInputChannel.
If we would just add [sourcecode language=”xml”]
[sourcecode language=”xml”]
[citrus] Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘fileInputChannelReceiver’: Initialization of bean failed; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert property value of type [org.springframework.integration.channel.DirectChannel] to required type
[org.springframework.integration.channel.PollableChannel] for property ‘channel’; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [org.springframework.integration.channel.DirectChannel]
to required type [org.springframework.integration.channel.PollableChannel] for property ‘channel’: no matching editors or conversion strategy found
[/sourcecode]
So Citrus expects some other type of channel. Adding [sourcecode language=”xml”]
Running the sample again will give us the next error :
[sourcecode language=”xml”]
[citrus] Caused by: org.w3c.dom.ls.LSException: Content is not allowed in prolog.
[citrus] at org.apache.xerces.parsers.DOMParserImpl.parse(Unknown Source)
[citrus] at com.consol.citrus.util.XMLUtils.parseMessagePayload(XMLUtils.java:333)
[citrus] at com.consol.citrus.validation.DefaultXMLMessageValidator.validateXMLSchema(DefaultXMLMessageValidator.java:300)
[citrus] at com.consol.citrus.validation.DefaultXMLMessageValidator.validateMessage(DefaultXMLMessageValidator.java:98)
[citrus] … 54 more
[citrus] Caused by: ::::1:1:0:Content is not allowed in prolog.
[citrus] at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
[citrus] at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
[citrus] at org.apache.xerces.impl.XMLScanner.reportFatalError(Unknown Source)
[citrus] at org.apache.xerces.impl.XMLDocumentScannerImpl$PrologDispatcher.dispatch(Unknown Source)
[citrus] at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
[citrus] at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
[citrus] at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
[citrus] at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
[citrus] … 58 more
[/sourcecode]
The inbound-adapter passes on the file 1 on 1 to the file channel. Since the channel expects a string instead of a file object we need to transform this file-object to a string-object. Spring Framework gives us a default Transformer for this.
To intercept the File-object before it gets stored on the MessageChannel we can add an ‘interceptor’, as argument to the call of the interceptor we define the ‘FileToStringTransformer’.
Secondly we need to config src/citrus/tests/com/consol/citrus/samples/greeting/jms/GreetingJmsTest.xml
[sourcecode language=”xml”]
[/sourcecode]
Only change in here compaired to part1 is the [sourcecode language=”xml”]
Now run the test again and see if the framework matches the generated file on filesystem with the payload we configurated.
Since i don’t do any transformations in the middleware the request payload should match the response payload.
[sourcecode language=”xml”]ant citrus.run.tests[/sourcecode]
..and see the results
[sourcecode language=”xml”]
[citrus] 19047 INFO port.LoggingReporter| TEST FINISHED: GreetingJmsTest
[citrus] 19047 INFO port.LoggingReporter| ————————————————————————
[citrus] 19063 INFO port.LoggingReporter| FINISH TESTSUITE citrus-samples-greeting
[citrus] 19063 INFO port.LoggingReporter| ————————————————————————
[citrus] 19063 INFO port.LoggingReporter| ________________________________________________________________________
[citrus] 19063 INFO port.LoggingReporter|
[citrus] 19079 INFO port.LoggingReporter| CITRUS TEST RESULTS
[citrus] 19079 INFO port.LoggingReporter|
[citrus] 19079 INFO port.LoggingReporter| GreetingJmsTest ……………………………………….. SUCCESS
[citrus] 19079 INFO port.LoggingReporter|
[citrus] 19079 INFO port.LoggingReporter| Total number of tests: 1
[citrus] 19079 INFO port.LoggingReporter| Skipped: 0 (0.0%)
[citrus] 19079 INFO port.LoggingReporter| Failed: 0 (0.0%)
[citrus] 19079 INFO port.LoggingReporter| Success: 1 (100.0%)
[/sourcecode]
Conclusion
I hope this gave you good overview on how to implement integration tests with the Citrus Framework. For me it’s an ideal way to test my Oracle Service Bus flows.
How do you guys think about it ? Or do you use other frameworks for testing?
Original blog