Question about using message headers/Exchange properties and route testing
Hi Camel users To process arbitrary logic in my Camel routes, I use simple bean calls. That is fine because I can test all these pieces of logic with standard unit tests. However, often the bean calls produce results that are saved in the message header (if I need to save it for later) or Exchange properties (if it is only needed in the current route). So my bean methods often look like this: public void setDocumentGuid(@Headers Map headers); The header-map is passed to add new headers, the method is simply called with "bean(bean, method)" in the route. My problem arised in the route tests where I mock away the whole bean. I can mock the method call, but I cannot add entries to the header- or property-maps. So if the header or property entry is expected later in the route, it fails. Therefore I moved to bean methods like this: public String setDocumentGuid(); The header-map is no more needed, since the header value is returned and the method is called with "setHeader(headerKey, bean(bean, method)" in the route. Now I can return whatever I like from the mock. But the problem returns if #1: I have multiple values or objects I would like to save. I cannot return them in the method (without creating a "transport object" or returning a map), so I need to add them to the headers or properties in the method, but then they are not existing when I mock the method call. #2: I would like to test a subroutes (direct:) that is expecting Exchange properties from the parent route. I cannot easily set these properties for the tests of the subroute (I probably could by injecting a processor for the test that sets them, but the most simple test would become quite complex). I would like to only test the correct message flow with route tests and therefore mock away all beans (that are already tested with unit-tests), but since my beans set message headers or properties they are like a route-extension and needed to execute the route correctly. Am I missing a basic Camel concept? How do you draw the line between route with headers/properties and "external" components like beans? Thanks for any help Stephan
Re: Question about using message headers/Exchange properties and route testing
Hi, I don’t think you need to use mock framework to mock the bean. You can just write a simple bean which implement the bean’s interface to setup the message headers and exchange properties for you camel route. -- Willem Jiang Red Hat, Inc. Web: http://www.redhat.com Blog: http://willemjiang.blogspot.com(http://willemjiang.blogspot.com/) (English) http://jnn.iteye.com(http://jnn.javaeye.com/) (Chinese) Twitter: willemjiang Weibo: 姜宁willem On December 30, 2013 at 4:36:53 PM, Stephan Burkard (sburk...@gmail.com) wrote: > > Hi Camel users > > To process arbitrary logic in my Camel routes, I use simple bean > calls. > That is fine because I can test all these pieces of logic with standard > unit tests. > > However, often the bean calls produce results that are saved > in the message > header (if I need to save it for later) or Exchange properties > (if it is > only needed in the current route). > > So my bean methods often look like this: > public void setDocumentGuid(@Headers Map > headers); > > The header-map is passed to add new headers, the method is simply > called > with "bean(bean, method)" in the route. > > My problem arised in the route tests where I mock away the whole > bean. I > can mock the method call, but I cannot add entries to the header- > or > property-maps. So if the header or property entry is expected > later in the > route, it fails. > > Therefore I moved to bean methods like this: > public String setDocumentGuid(); > > The header-map is no more needed, since the header value is returned > and > the method is called with "setHeader(headerKey, bean(bean, > method)" in the > route. Now I can return whatever I like from the mock. > > But the problem returns if > > #1: I have multiple values or objects I would like to save. I cannot > return > them in the method (without creating a "transport object" or > returning a > map), so I need to add them to the headers or properties in the method, > but > then they are not existing when I mock the method call. > > #2: I would like to test a subroutes (direct:) that is expecting > Exchange > properties from the parent route. I cannot easily set these properties > for > the tests of the subroute (I probably could by injecting a processor > for > the test that sets them, but the most simple test would become > quite > complex). > > I would like to only test the correct message flow with route tests > and > therefore mock away all beans (that are already tested with unit-tests), > but since my beans set message headers or properties they are > like a > route-extension and needed to execute the route correctly. > > Am I missing a basic Camel concept? How do you draw the line between > route > with headers/properties and "external" components like beans? > > Thanks for any help > Stephan >
Re: Question about using message headers/Exchange properties and route testing
Hi Stephan, > My problem arised in the route tests where I mock away the whole bean. I > can mock the method call, but I cannot add entries to the header- or > property-maps. So if the header or property entry is expected later in the > route, it fails. Keep in mind that in tests you can send messages via ProducerTemplate with some arbitatry headers/properties. Since headers and properties are propagated with the messages down the route, you can set test fixtures this way. producerTemplate.sendBodyAndHeader("direct:test", "message", "expected_header_key", "expected_header_value"); In production environment "expected_header_key" could be set by your bean, but for unit tests you would pass it explicitly as a fixture to the producer template initiating the test. This approach usually works for me. For more complicated cases (for example when you need to alter the header within the route), you can use AdviceWith [1] or interceptors [2]. Cheers. [1] http://camel.apache.org/advicewith.html [2] http://camel.apache.org/intercept.html -- Henryk Konsek http://henryk-konsek.blogspot.com
Re: Question about using message headers/Exchange properties and route testing
@Henryk: Yes, that works fine for message headers, I use it a lot to pass expected message headers. But it is not possible for Exchange properties. @Willem: Yes, that's true. It feels a bit "cumbersome", but it works. Based on your answers, I guess there is no fundamental Camel concept I am missing, but simply the Camel best practices that need to mature in my Camel routes and tests :-) Thanks a lot Stephan On Mon, Dec 30, 2013 at 10:22 AM, Willem Jiang wrote: > Hi, > > I don’t think you need to use mock framework to mock the bean. > You can just write a simple bean which implement the bean’s interface to > setup the message headers and exchange properties for you camel route. > > -- > Willem Jiang > > Red Hat, Inc. > Web: http://www.redhat.com > Blog: http://willemjiang.blogspot.com(http://willemjiang.blogspot.com/) > (English) > http://jnn.iteye.com(http://jnn.javaeye.com/) (Chinese) > Twitter: willemjiang > Weibo: 姜宁willem > > > > On December 30, 2013 at 4:36:53 PM, Stephan Burkard (sburk...@gmail.com) > wrote: > > > > Hi Camel users > > > > To process arbitrary logic in my Camel routes, I use simple bean > > calls. > > That is fine because I can test all these pieces of logic with standard > > unit tests. > > > > However, often the bean calls produce results that are saved > > in the message > > header (if I need to save it for later) or Exchange properties > > (if it is > > only needed in the current route). > > > > So my bean methods often look like this: > > public void setDocumentGuid(@Headers Map > > headers); > > > > The header-map is passed to add new headers, the method is simply > > called > > with "bean(bean, method)" in the route. > > > > My problem arised in the route tests where I mock away the whole > > bean. I > > can mock the method call, but I cannot add entries to the header- > > or > > property-maps. So if the header or property entry is expected > > later in the > > route, it fails. > > > > Therefore I moved to bean methods like this: > > public String setDocumentGuid(); > > > > The header-map is no more needed, since the header value is returned > > and > > the method is called with "setHeader(headerKey, bean(bean, > > method)" in the > > route. Now I can return whatever I like from the mock. > > > > But the problem returns if > > > > #1: I have multiple values or objects I would like to save. I cannot > > return > > them in the method (without creating a "transport object" or > > returning a > > map), so I need to add them to the headers or properties in the method, > > but > > then they are not existing when I mock the method call. > > > > #2: I would like to test a subroutes (direct:) that is expecting > > Exchange > > properties from the parent route. I cannot easily set these properties > > for > > the tests of the subroute (I probably could by injecting a processor > > for > > the test that sets them, but the most simple test would become > > quite > > complex). > > > > I would like to only test the correct message flow with route tests > > and > > therefore mock away all beans (that are already tested with unit-tests), > > but since my beans set message headers or properties they are > > like a > > route-extension and needed to execute the route correctly. > > > > Am I missing a basic Camel concept? How do you draw the line between > > route > > with headers/properties and "external" components like beans? > > > > Thanks for any help > > Stephan > > > >
Re: Question about using message headers/Exchange properties and route testing
> @Henryk: Yes, that works fine for message headers, I use it a lot to pass > expected message headers. But it is not possible for Exchange properties. Are you sure? :) Exchange properties are propagated as well as headers. Can you show me an example, where the properties are not propagated down the route? > @Willem: Yes, that's true. It feels a bit "cumbersome", but it works. Yeah, the whole point of using mocking library is to reduce the boilerplate, so I won't implement interfaces as well. Also not always you would like to introduce interface for the bean and tests design shouldn't force you to do so. There is also a chance that you might work with 3rd party beans (developed by the other team for example) which you can't refactor. You definitely need a way to live with the mocks in your routes :) . > Based on your answers, I guess there is no fundamental Camel concept I am > missing, but simply the Camel best practices that need to mature in my > Camel routes and tests :-) Yes. There is no hidden Camel feature that could help you here. :) -- Henryk Konsek http://henryk-konsek.blogspot.com
Re: Question about using message headers/Exchange properties and route testing
Hi Henryk > Are you sure? :) Exchange properties are propagated as well as > headers. Can you show me an example, where the properties are not > propagated down the route? Wow, I just realized that there are producer methods to send a body and a property. I never noticed them before because I always used the ones for body and header(s). But however, I need to send expected headers into most of my tests, so I would need to have a method that takes body, header-map and a property or even a property-map. At least in my current Camel version (2.9.x) I didn't found a way to do this. Am I wrong? Have you another pleasant surprise for me? :) Thanks a lot! Stephan On Tue, Dec 31, 2013 at 11:06 AM, Henryk Konsek wrote: > > @Henryk: Yes, that works fine for message headers, I use it a lot to pass > > expected message headers. But it is not possible for Exchange properties. > > Are you sure? :) Exchange properties are propagated as well as > headers. Can you show me an example, where the properties are not > propagated down the route? > > > @Willem: Yes, that's true. It feels a bit "cumbersome", but it works. > > Yeah, the whole point of using mocking library is to reduce the > boilerplate, so I won't implement interfaces as well. Also not always > you would like to introduce interface for the bean and tests design > shouldn't force you to do so. There is also a chance that you might > work with 3rd party beans (developed by the other team for example) > which you can't refactor. You definitely need a way to live with the > mocks in your routes :) . > > > Based on your answers, I guess there is no fundamental Camel concept I am > > missing, but simply the Camel best practices that need to mature in my > > Camel routes and tests :-) > > Yes. There is no hidden Camel feature that could help you here. :) > > -- > Henryk Konsek > http://henryk-konsek.blogspot.com >
Re: Question about using message headers/Exchange properties and route testing
Just use the send/request method that takes a processor, and then use an inlined processor to set the headers/properties/body on the exchange in message. There is also an ExchangeBuilder AFAIR that you may use as well. Then you can use that to create an exchange, to send with the produce template. On Fri, Jan 3, 2014 at 12:41 PM, Stephan Burkard wrote: > Hi Henryk > >> Are you sure? :) Exchange properties are propagated as well as >> headers. Can you show me an example, where the properties are not >> propagated down the route? > > Wow, I just realized that there are producer methods to send a body and a > property. I never noticed them before because I always used the ones for > body and header(s). > > But however, I need to send expected headers into most of my tests, so I > would need to have a method that takes body, header-map and a property or > even a property-map. At least in my current Camel version (2.9.x) I didn't > found a way to do this. Am I wrong? Have you another pleasant surprise for > me? :) > > Thanks a lot! > Stephan > > > > On Tue, Dec 31, 2013 at 11:06 AM, Henryk Konsek wrote: > >> > @Henryk: Yes, that works fine for message headers, I use it a lot to pass >> > expected message headers. But it is not possible for Exchange properties. >> >> Are you sure? :) Exchange properties are propagated as well as >> headers. Can you show me an example, where the properties are not >> propagated down the route? >> >> > @Willem: Yes, that's true. It feels a bit "cumbersome", but it works. >> >> Yeah, the whole point of using mocking library is to reduce the >> boilerplate, so I won't implement interfaces as well. Also not always >> you would like to introduce interface for the bean and tests design >> shouldn't force you to do so. There is also a chance that you might >> work with 3rd party beans (developed by the other team for example) >> which you can't refactor. You definitely need a way to live with the >> mocks in your routes :) . >> >> > Based on your answers, I guess there is no fundamental Camel concept I am >> > missing, but simply the Camel best practices that need to mature in my >> > Camel routes and tests :-) >> >> Yes. There is no hidden Camel feature that could help you here. :) >> >> -- >> Henryk Konsek >> http://henryk-konsek.blogspot.com >> -- Claus Ibsen - Red Hat, Inc. Email: cib...@redhat.com 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
Re: Question about using message headers/Exchange properties and route testing
> There is also an ExchangeBuilder AFAIR that you may use as well. Then > you can use that to create an exchange, to send with the produce > template. ExchangeBuilder is cool indeed, I forgot about it. :) BTW Probably having bean mocking API similar to the one presented below would be a nice addition to our testing API. However creating such API is not as trivial as it might look like, because of the rich bean binding capabilities that it should support. @Bean // Spring Java config Example MyBean myBean() { return MockBean.createMockBean(MyBean.class). removeHeader("foo"). // this mock will remove given header from exchange addProperty("prop"). // add property that couldn't be added before assertHeader("bar").isEqualTo("baz"); // and make some assertions } from(...).bean("myBean", "myMethod").to(...); -- Henryk Konsek http://henryk-konsek.blogspot.com
Re: Question about using message headers/Exchange properties and route testing
Thank you very much Claus, great hints! I found the ExchangeBuilder in Camel 2.11 and later, so it is not available in my version, but I have to keep that in mind. However, I found a CamelTestSupport.createExchangeWithBody() method that seems to create an Exchange from my body object. Then I could add my headers and properties and use the send-method that takes an Exchange. Or I use the send-method that takes a processor as you also suggested. Regards Stephan On Fri, Jan 3, 2014 at 1:40 PM, Henryk Konsek wrote: > > There is also an ExchangeBuilder AFAIR that you may use as well. Then > > you can use that to create an exchange, to send with the produce > > template. > > ExchangeBuilder is cool indeed, I forgot about it. :) > > BTW Probably having bean mocking API similar to the one presented > below would be a nice addition to our testing API. However creating > such API is not as trivial as it might look like, because of the rich > bean binding capabilities that it should support. > > @Bean // Spring Java config Example > MyBean myBean() { > return MockBean.createMockBean(MyBean.class). > removeHeader("foo"). // this mock will remove given header from > exchange > addProperty("prop"). // add property that couldn't be added before > assertHeader("bar").isEqualTo("baz"); // and make some assertions > } > > from(...).bean("myBean", "myMethod").to(...); > > -- > Henryk Konsek > http://henryk-konsek.blogspot.com >