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
8 Responses to “EAI/Oracle Service Bus testing with Citrus Framework, part2”
Great post! I think it is a very good sample for the handshake between Citrus and Spring Integration adapters. With this test setup Citrus can use all Spring Integration adapter implementations, which is great! I will definitely add more descriptions to the Citrus reference documentation, promised 🙂 Thank you for the article!
[…] EAI/Oracle Service Bus testing with Citrus Framework, part2 « Oracle .. Java .. OpenSource .. … […]
It looks very useful for a developer to make automated message based tests. But it’s a bit complex with XML and Java for most testers to develop or maintain. What are opinions about similar tools that driven from a GUI? There are a few out there but GH Tester is one that I am familiar with. It would be very interesting to hear peoples opinions about the pros and cons of the two different approaches given that their goals and broad functionality are very similar – message based automated testing of diverse interfaces.
I agree it’s a bit to technical for the average tester. I’m not familiar with the tools used by the testers itself, but i don’t think there is one best way to go on those. It depends on the profile of your testers to see what technical implementation or methodology they use. Does GH gives you the opportunity to maintain already build testcases from the developers, or do you need to create them all by yourself, from scratch
[…] 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 […]
Hi Eric,
Would it be possible to deploy the system under test on a different host (or a different container) than Citrus. In this case what would happen if the system under test is referencing a queue through e.g. jndi.
In my opinion in this case the queue is out of control in Citrus because it’s not a Spring wired managed connection.
The same counts for referencing a web service through other means than Spring.
Am I right here and if so are there any workarounds? In other words must the system under test itself be Spring managed?
If you think I am misunderstanding Citrus than please explain.
Greetings,
Ton
[…] how to use Citrus framework which can plug with maven to provide automation of unit tests. http://www.xenta.nl/blog/2010/04/12/eaioracle-service-bus-testing-with-citrus-framework-part2/ […]
[…] http://www.xenta.nl/blog/2010/04/12/eaioracle-service-bus-testing-with-citrus-framework-part2/ […]