Unit Testing Question

classic Classic list List threaded Threaded
15 messages Options
Reply | Threaded
Open this post in threaded view
|

Unit Testing Question

Castyn
Greetings, I have a question around unit testing within Camel as I am fairly new to it.  I have a process:

        public void setProcessStatus(Exchange exchange) throws Exception {
                String processName = exchange.getIn().getHeader("process_name", String.class);
                String processStatus = exchange.getIn().getHeader("process_status", String.class);
               
                JdbcEndpoint e = (JdbcEndpoint) exchange.getContext().getEndpoint("jdbc:mtgsServiceDataSource");
                JdbcProducer p = (JdbcProducer) e.createProducer();
                exchange.getIn().setBody(getUpdateProcessStatus(processName,processStatus));
               
                p.process(exchange);

                int result = (Integer) exchange.getOut().getHeader("CamelJdbcUpdateCount", Integer.class);

                if(result <= 0)
                        throw new InvalidProcessStateException("Process Status unable to be updated");
               
        }

I am curious how it would be possible to setup the necessary aspects for a unit test of this method?  How do you setup an entire exchange in a unit test, or is there capabilities built in somewhere I am unaware of?

Thanks for any help
Reply | Threaded
Open this post in threaded view
|

Re: Unit Testing Question

Claus Ibsen-2
Hi

There is a lot of information about testing at
http://camel.apache.org/testing

And also in the books published
http://camel.apache.org/books


On Tue, Jan 14, 2014 at 9:53 PM, Castyn <[hidden email]> wrote:

> Greetings, I have a question around unit testing within Camel as I am fairly
> new to it.  I have a process:
>
>         public void setProcessStatus(Exchange exchange) throws Exception {
>                 String processName = exchange.getIn().getHeader("process_name",
> String.class);
>                 String processStatus = exchange.getIn().getHeader("process_status",
> String.class);
>
>                 JdbcEndpoint e = (JdbcEndpoint)
> exchange.getContext().getEndpoint("jdbc:mtgsServiceDataSource");
>                 JdbcProducer p = (JdbcProducer) e.createProducer();
>
> exchange.getIn().setBody(getUpdateProcessStatus(processName,processStatus));
>
>                 p.process(exchange);
>
>                 int result = (Integer) exchange.getOut().getHeader("CamelJdbcUpdateCount",
> Integer.class);
>
>                 if(result <= 0)
>                         throw new InvalidProcessStateException("Process Status unable to be
> updated");
>
>         }
>
> I am curious how it would be possible to setup the necessary aspects for a
> unit test of this method?  How do you setup an entire exchange in a unit
> test, or is there capabilities built in somewhere I am unaware of?
>
> Thanks for any help
>
>
>
> --
> View this message in context: http://camel.465427.n5.nabble.com/Unit-Testing-Question-tp5745966.html
> Sent from the Camel - Users mailing list archive at Nabble.com.



--
Claus Ibsen
-----------------
Red Hat, Inc.
Email: [hidden email]
Twitter: davsclaus
Blog: http://davsclaus.com
Author of Camel in Action: http://www.manning.com/ibsen
Make your Camel applications look hawt, try: http://hawt.io
Reply | Threaded
Open this post in threaded view
|

Re: Unit Testing Question

hekonsek
In reply to this post by Castyn
Hi,

> I am curious how it would be possible to setup the necessary aspects for a
> unit test of this method?  How do you setup an entire exchange in a unit
> test, or is there capabilities built in somewhere I am unaware of?

You can set up exchange fixtures with the appropriate ProducerTemplate
methods. For example:

producerTemplate.sendBodyAndHeader("direct:test", "testMessage",
"headerKey", "headerValue");

I would also suggest you to split your processor into smaller units of
processing. You could for example try to call Camel components (like
JDBC) via routes instead of fetching them and calling explicitly in
the processor. You might also consider extracting
getUpdateProcessStatus() method into dedicated bean and wiring it into
your route via bean component [1]. To more fine-grained is you
processing flow, the easier will it be to test it.

Cheers.

[1] http://camel.apache.org/bean.html

--
Henryk Konsek
http://henryk-konsek.blogspot.com
Reply | Threaded
Open this post in threaded view
|

Re: Unit Testing Question

Castyn
In most cases in my code I utilize processors to do exactly what you mention.  This situation is sort of a special case where I wanted to house all of the route logic within a single class in the java DSL.  Typically in this project I have setup to use camel-jdbc, camel-cxf, etc as their own endpoints and configured the beans surrounding the process within the spring DSL.

My question is geared at understanding what goes into unit testing a processor with a test exchange and how I would accomplish that in this particular case.   I'll look into the producer templates, as well as the Camel In Action book I have.   I just know Camel is one of those frameworks where the number of ways to accomplish something is great, and that often causes me some issue when getting started with a new aspect of it.
Reply | Threaded
Open this post in threaded view
|

Re: Unit Testing Question

Castyn
So to go a bit further, assuming I setup the producer template to mimic and exchange to test this method, how then do I send that exchange to the method?  Do I just instantiate the processor within the test case and use the template.send(Processor) method signature to do this?  If so how then do I see the out exchange from the template?  

Also if it is not a processor and just a bean with a method that executes on the exchange, how then would I even send the producer template exchange to that method?
Reply | Threaded
Open this post in threaded view
|

Re: Unit Testing Question

Claus Ibsen-2
Since your bean with the setProcessStatus method requires an exchange,
then you should not really use the producer template.

Just create a new DefaultExchange and popular it with data, and call
the method. Just like regular java code.





On Wed, Jan 15, 2014 at 6:48 PM, Castyn <[hidden email]> wrote:

> So to go a bit further, assuming I setup the producer template to mimic and
> exchange to test this method, how then do I send that exchange to the
> method?  Do I just instantiate the processor within the test case and use
> the template.send(Processor) method signature to do this?  If so how then do
> I see the out exchange from the template?
>
> Also if it is not a processor and just a bean with a method that executes on
> the exchange, how then would I even send the producer template exchange to
> that method?
>
>
>
>
> --
> View this message in context: http://camel.465427.n5.nabble.com/Unit-Testing-Question-tp5745966p5745999.html
> Sent from the Camel - Users mailing list archive at Nabble.com.



--
Claus Ibsen
-----------------
Red Hat, Inc.
Email: [hidden email]
Twitter: davsclaus
Blog: http://davsclaus.com
Author of Camel in Action: http://www.manning.com/ibsen
Make your Camel applications look hawt, try: http://hawt.io
Reply | Threaded
Open this post in threaded view
|

Re: Unit Testing Question

cemmersb
In reply to this post by Castyn
Hi

in case you want to test the entire route, I’d recommend using a producer template.
The ProducerTemplate can send an exchange via:

template.send(“<a href="your://endoint/uri”">your://endoint/uri”, exchange);

Best,

Christoph

On 15 Jan 2014, at 18:48, Castyn <[hidden email]> wrote:

So to go a bit further, assuming I setup the producer template to mimic and
exchange to test this method, how then do I send that exchange to the
method?  Do I just instantiate the processor within the test case and use
the template.send(Processor) method signature to do this?  If so how then do
I see the out exchange from the template?  

Also if it is not a processor and just a bean with a method that executes on
the exchange, how then would I even send the producer template exchange to
that method?




--
View this message in context: http://camel.465427.n5.nabble.com/Unit-Testing-Question-tp5745966p5745999.html
Sent from the Camel - Users mailing list archive at Nabble.com.


signature.asc (465 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Unit Testing Question

Castyn
This post was updated on .
In reply to this post by Claus Ibsen-2
I've been reading over all of the test documentation and Mock documentation.  It seems that I should be able to just setup a mock endpoint for the URI of the processor and use the producer template to send the information to the endpoint and run the asserts on that endpoint.  Is that a proper usage?

I don't really understand yet how mock endpoints work, I am seeking a simple example to help get me over this.

Let's say I have a processor testProc that just does something trivial such as:

public class testProc implements Processor {
        @Override
        public void process(Exchange exchange) throws Exception {
                exchange.getIn().setHeader("myHeader", "Yay");
        }
}

let's say this processor is defined as a bean:
<bean id="myProcessor" class="com.test.testProc"/>

How do you use the mock and producer template to test this within a test class?  How do I wire the mock endpoint to the processor uri?  What do I need to do to setup the mock endpoint for this

public class SimpleTest extends CamelTestSupport{

        @EndpointInject(uri = "mock:myProcessor")
        protected MockEndpoint resultEndpoint;  
         
        @Produce(uri = "direct:start")
        protected ProducerTemplate template;
         
        @Test
        public void procTest() throws Exception {
                resultEndpoint.message(0).header("myHeader").isEqualTo("Yay");
                template.sendBody("Test");
                resultEndpoint.assertIsSatisfied();
        }
}

So assuming this sort of general flow is correct, I suppose my main hurdle of understanding is based on not knowing how a mock endpoint can get wired to an existing uri endpoint in the context.  I saw some mention of context.resolveEndpoint(), but in the version I am using (Camel 2.8) I actually don't see a resolve endpoint on org.apache.camel.test.CamelTestSupport.context.  So how do I modify this to run for the proper processor uri?
Reply | Threaded
Open this post in threaded view
|

Re: Unit Testing Question

hekonsek
> I don't really understand yet how mock endpoints work, I am seeking a simple
> example to help get me over this.

You can test your processor with Mock endpoint by using the latter to
catch exchange processed by the former.

// Fixtures
from("direct:test").process(new testProc()).to("mock:test");

// Given
MockEndpoint resultEndpoint = getMockEndpoint("mock:test");
resultEndpoint.expectedMessageCount(1);
resultEndpoint.message(0).header("myHeader").isEqualTo("Yay");

// When
template.sendBody("direct:test", "Test");

// Then
resultEndpoint.assertIsSatisfied();

Cheers.

--
Henryk Konsek
http://henryk-konsek.blogspot.com
Reply | Threaded
Open this post in threaded view
|

Re: Unit Testing Question

kraythe
There are a number of examples on the camel testing page. However I can
provide perhaps some information. Mock endpoints are just recorders of
information the previous poster used in example. Normally an endpoint
doesn't keep track of what exchanges go through it but mock ones do. You
can also mock an endpoint in an existing route with adviceWith() in a unit
test. This will insert an interceptor into the route before the endpoint
that will record the data going through. If you do mockEndpointsAndSkip()
the component mocking will not get executed.

See the following pages for more info then come back if you have further
questions:
http://camel.apache.org/advicewith.html
http://camel.apache.org/camel-test.html



*Robert Simmons Jr. MSc. - Lead Java Architect @ EA*
*Author of: Hardcore Java (2003) and Maintainable Java (2012)*
*LinkedIn: **http://www.linkedin.com/pub/robert-simmons/40/852/a39
<http://www.linkedin.com/pub/robert-simmons/40/852/a39>*


On Fri, Jan 17, 2014 at 8:24 AM, Henryk Konsek <[hidden email]> wrote:

> > I don't really understand yet how mock endpoints work, I am seeking a
> simple
> > example to help get me over this.
>
> You can test your processor with Mock endpoint by using the latter to
> catch exchange processed by the former.
>
> // Fixtures
> from("direct:test").process(new testProc()).to("mock:test");
>
> // Given
> MockEndpoint resultEndpoint = getMockEndpoint("mock:test");
> resultEndpoint.expectedMessageCount(1);
> resultEndpoint.message(0).header("myHeader").isEqualTo("Yay");
>
> // When
> template.sendBody("direct:test", "Test");
>
> // Then
> resultEndpoint.assertIsSatisfied();
>
> Cheers.
>
> --
> Henryk Konsek
> http://henryk-konsek.blogspot.com
>
Reply | Threaded
Open this post in threaded view
|

Re: Unit Testing Question

Castyn
This post was updated on .
In reply to this post by hekonsek
For the fixtures in the example, does that need to be embedded into a Routebuilder?  I'm still trying to setup this simple example but unsure how the fixture here is actually invoked.  Currently all of my routes are actually created in the spring DSL as well.  Any elaboration on this would be helpful.

Edit:  For example, would you do something like

    // Fixtures
    RouteBuilder builder = new RouteBuilder() {
       public void configure() {
        from("direct:test").process(new TestProc()).to("mock:test");
       }
    };    
   
    builder.addRoutesToCamelContext(context);


Edit 2: I am getting an oddity when attempting to run now, I tried to use the following:

public class ApplicationStatusProcessorTest extends CamelTestSupport {
 
    @Test
    public void simpleTest() throws Exception {
    // Fixtures
    RouteBuilder builder = new RouteBuilder() {
       public void configure() {
        from("direct:test").process(new ApplicationStatusProcessor()).to("mock:test");
       }
    };    
   
    builder.addRoutesToCamelContext(context);

    // Given
    MockEndpoint resultEndpoint = getMockEndpoint("mock:test");
    resultEndpoint.expectedMessageCount(1);
    resultEndpoint.message(0).header("myHeader").isEqualTo("Yay");

    // When
    template.sendBody("direct:test", "Test");

    // Then
    resultEndpoint.assertIsSatisfied();    
    }
}

For some reason now surefire is saying
Failed tests:
  TestSuite$1.warning No tests found in com.ihg.atp.ess.processor.ApplicationStatusProcessorTest

I am using camel 2.8, not sure why it would say no tests found.
Reply | Threaded
Open this post in threaded view
|

Re: Unit Testing Question

Castyn
Still have not been able to figure this out.  I tried few simple purely JUnit tests and they worked fine and were executed by surefire with no issues, but for some reason once I extend to CamelTestSupport it says no tests were found no matter what kind of tests are there.  Could this be a version issue?

I am including

<dependency>
        <groupId>org.apache.camel</groupId>
        <artifactId>camel-test</artifactId>
        <version>2.8.0</version>
</dependency>

in my pom and currently running Camel 2.8.0-fuse-01-13.  The includes in the test files are simply

import org.apache.camel.test.CamelTestSupport;
import org.junit.Test;
Reply | Threaded
Open this post in threaded view
|

Re: Unit Testing Question

Castyn
I changed my import of org.apache.camel.test.CamelTestSupport to org.apache.camel.test.junit4.CamelTestSupport, and now it generates a different error within surefire.

Tests in error:
  SimpleTest>TestSupport.<clinit>:55 » NoClassDefFound org/s...
  SimpleTest.com.ihg.atp.ess.processor.SimpleTest » NoClassDefFound


Here is the full unit test class currently.

import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.junit.Test;


public class SimpleTest extends CamelTestSupport {
 
        @Override
        protected RouteBuilder createRouteBuilder() throws Exception {
                return new RouteBuilder() {
                        public void configure() {
        from("direct:test").process(new TestProcessor()).to("mock:test");
       }
                };
        }
       
    @Test
    public void simpleTest() throws Exception {
    MockEndpoint resultEndpoint = getMockEndpoint("mock:test");
    resultEndpoint.expectedMessageCount(1);
    resultEndpoint.message(0).header("myHeader").isEqualTo("Yay");

    template.sendBody("direct:test", "Test");

    resultEndpoint.assertIsSatisfied();    
    }
Reply | Threaded
Open this post in threaded view
|

Re: Unit Testing Question

Willem.Jiang
Administrator
Can you double check the camel jars in your class path to see if there is another version of camel jar in your class path?

BTW, can you tell us which ClassDef is not found?
Reply | Threaded
Open this post in threaded view
|

Re: Unit Testing Question

Castyn
I figured it out, was an sl4j version issue.  Seems things are working now so I appreciate the help!