Return-Path: X-Original-To: apmail-camel-users-archive@www.apache.org Delivered-To: apmail-camel-users-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 447E4113C5 for ; Wed, 11 Jun 2014 23:09:04 +0000 (UTC) Received: (qmail 68693 invoked by uid 500); 11 Jun 2014 23:09:03 -0000 Delivered-To: apmail-camel-users-archive@camel.apache.org Received: (qmail 68543 invoked by uid 500); 11 Jun 2014 23:09:02 -0000 Mailing-List: contact users-help@camel.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: users@camel.apache.org Delivered-To: mailing list users@camel.apache.org Received: (qmail 68529 invoked by uid 99); 11 Jun 2014 23:09:02 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 11 Jun 2014 23:09:02 +0000 X-ASF-Spam-Status: No, hits=-0.0 required=5.0 tests=RCVD_IN_DNSWL_NONE,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (nike.apache.org: domain of darth.minhster@gmail.com designates 209.85.192.170 as permitted sender) Received: from [209.85.192.170] (HELO mail-pd0-f170.google.com) (209.85.192.170) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 11 Jun 2014 23:08:59 +0000 Received: by mail-pd0-f170.google.com with SMTP id g10so291109pdj.15 for ; Wed, 11 Jun 2014 16:08:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=content-type:mime-version:subject:from:in-reply-to:date :content-transfer-encoding:message-id:references:to; bh=LMs6UvBxhdVVQ4RwmgE3RxMl8Ad6ev8ej3LJcoxq1XE=; b=wH+zmUuEVMNrF4PtUlcscaAQTaTDD3/bw8pfXZha+TReDcJxdiPmWOixL1bFWngSB6 PPAx+FPxjkw4F6PeTNZjUBBjVu7/D3o+3dsBN0ATTs3zhgN38oUXKIPVHq5q+mL/+ABF bPRejEfHkWIq5iZuQ8lS2t48FY3ji61qe/3Jva7FvxJWGtqoDpWlXojGa9yYdUc+jAIX SACyRBT3h/GSJ7HHzCYWsxrsQmKcCVD2nrTRBb9Miqxiy7UyxtCb6D97w7munb9Gauln Y8vJCHQUBcxHR4ImECATdaA3MubS3ZaxPunnnoWZ2mtc7d8oTUQDOEqJZYxe7Ycfbt4r lAfw== X-Received: by 10.68.135.67 with SMTP id pq3mr8437227pbb.165.1402528114766; Wed, 11 Jun 2014 16:08:34 -0700 (PDT) Received: from [192.168.202.25] (gw01.winning.com.au. [61.8.3.180]) by mx.google.com with ESMTPSA id no9sm76864094pbc.83.2014.06.11.16.08.33 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 11 Jun 2014 16:08:34 -0700 (PDT) Content-Type: text/plain; charset=us-ascii Mime-Version: 1.0 (Mac OS X Mail 6.6 \(1510\)) Subject: Re: Mocking SQL results in a route From: Minh Tran In-Reply-To: <3F0314F6-7328-4B34-BA9D-11E88D3CD76A@raibledesigns.com> Date: Thu, 12 Jun 2014 09:08:30 +1000 Content-Transfer-Encoding: quoted-printable Message-Id: <6083571C-95E5-459F-97A2-CDB009DC9ED1@gmail.com> References: <3F0314F6-7328-4B34-BA9D-11E88D3CD76A@raibledesigns.com> To: users@camel.apache.org X-Mailer: Apple Mail (2.1510) X-Virus-Checked: Checked by ClamAV on apache.org If you're using Spring, I recommend not extending any of the Camel Test = classes and using the Camel Enhanced Spring Test as described here http://camel.apache.org/spring-testing.html The docs take a bit of getting use to because it describes several = different ways of testing via Spring but you just have to skip to the = Camel Enhanced Spring Test bits. It also doesn't describe how to test = using a JavaConfig class very well IMO. It only describes how to do this = by extending AbstractJUnit4SpringContextTests which is a really old way = of doing spring unit tests. I had to do a lot of experimenting to get it = to work without extending this class. Here's an example I had, the only difference is my JavaConfig is = embedded into my unit test class, but there's no reason you couldn't = refer to an existing class. If you want to mock and skip your sql or = soap calls, then instead of using @MockEndPoints, use = @MockEndPointsAndSkip. Look further down to see some gotchas that I = encountered in all of this. @RunWith(CamelSpringJUnit4ClassRunner.class) @ContextConfiguration(loader =3D = CamelSpringDelegatingTestContextLoader.class, classes =3D = RegexTest.JavaConfig.class) @MockEndpoints @DirtiesContext(classMode =3D ClassMode.AFTER_EACH_TEST_METHOD) public class RegexTest { @Produce(uri =3D "direct:start") private ProducerTemplate producerTemplate; @EndpointInject(uri =3D "mock:direct:match") private MockEndpoint matchEndpoint; @EndpointInject(uri =3D "mock:direct:nomatch") private MockEndpoint noMatchEndpoint; @Configuration public static class JavaConfig extends = SingleRouteCamelConfiguration { @Override public RouteBuilder route() { return new RouteBuilder() { @Override public void configure() throws Exception = { = from("direct:start").to("log:blah?showProperties=3Dtrue").log("${property.= scaleResponse.message}").choice().when() = .simple("resource:classpath:simple/item_not_exists.txt").to("direct:match"= ).otherwise().to("direct:nomatch").end(); = from("direct:match").log("matched"); from("direct:nomatch").log("no = match"); = this.getContext().setTracing(true); } }; } } @After public void afterTest() throws InterruptedException { matchEndpoint.assertIsSatisfied(); noMatchEndpoint.assertIsSatisfied(); } @Test public void testMatch() { InterfaceResponse response =3D new InterfaceResponse(); response.setMessage("ITEM XML Download ended. : Item = \"blah\" does not exist. - "); matchEndpoint.expectedMessageCount(1); producerTemplate.sendBodyAndProperty(null, = "scaleResponse", response); } } The regex you provide to mockendpointandskip and mock endpoint is = important to get right. I didn't add any regex to my example above = because mocking all endpoints (the default) was ok in my example. if you = get this regex wrong, camel doesn't warn you. You can turn on camel = logging to see whether it has mocked your endpoint correctly or not. It = should say something like the following. That's how you know it is = working.=20 INFO org.apache.camel.impl.InterceptSendToMockEndpointStrategy - = Adviced endpoint [direct://start] with mock endpoint [mock:direct:start] The regex value matching is a bit strange, if it doesn't match your = endpoint even though you are absolutely sure it is correct, try tacking = on ".*" on the end of it, this fixed it up for me many times. IMO I = think it's a bug in the camel regex matching somewhere. When you do the @EndpointInject uri, make sure you prepend with "mock" = and don't include anything pass the "?" in your uri. This wasn't obvious = to me. And again camel won't warn you if you get this wrong. @DirtiesContext is a must otherwise you get strange behaviour once one = test starts failing. Hope that helps. On 12/06/2014, at 8:27 AM, Matt Raible wrote: > Thanks for the advice. I bought the book, read chapter 6 and I'm = trying to use the advice builder. Chapter 6 talks about using mocks = quite a bit, which seems useful in building a route, but not when it's = already built. >=20 > My routes are configured with Spring and JavaConfig in a CamelConfig = class. When I try to use CamelTestSupport as my parent class, the = context doesn't have any route definitions in it. In other words, = context.getRouteDefinitions() returns an empty list. How do I get = CamelTestSupport to recognize my routes configured in Spring? Or is it = possible to inject the context and template and use adviceWith w/o = extending CamelTestSupport? >=20 > Thanks, >=20 > Matt >=20 > @RunWith(SpringJUnit4ClassRunner.class) > @ContextConfiguration(classes =3D CamelConfig.class) > public class FooRouteTests extends CamelTestSupport { >=20 > @Test > public void testAdvised() throws Exception { > = context.getRouteDefinition("routeId").adviceWith(context, new = RouteBuilder() { > @Override > public void configure() throws Exception { > // intercept sending to mock:foo and do = something else > interceptSendToEndpoint("sql:*") > = .skipSendToOriginalEndpoint() > .to("log:foo") > .to("mock:advised"); > } > }); > // we must manually start when we are done with all the = advice with > context.start(); >=20 > template.sendBody("direct:foo", "bar"); >=20 > getMockEndpoint("mock:advised").expectedMessageCount(1); > assertMockEndpointsSatisfied(); > } >=20 > @Override > public boolean isUseAdviceWith() { > // tell we are using advice with, which allows us to = advice the route > // before Camel is being started, and thus can replace = sql with something else. > return true; > } >=20 > On Jun 11, 2014, at 12:16 PM, Claus Ibsen = wrote: >=20 >> Hi >>=20 >> Yeah if you have Camel in Action book, read chapter 6. >>=20 >> And see bottom of this page >> http://camel.apache.org/testing >>=20 >> The advice builder is quite nifty and can "rework" the routes before = testing. >>=20 >>=20 >> On Wed, Jun 11, 2014 at 8:10 PM, Matt Raible = wrote: >>> Hello, >>>=20 >>> I have a route that looks as follows: >>>=20 >>> from(uri) >>> .to("log:input") >>> = .recipientList(simple("direct:${header.operationName}")); >>> from("direct:lookup") >>> .process(new Processor() { >>> public void process(Exchange = exchange) throws Exception { >>> // grab parameters = from request and set as headers for SQL statement >>> } >>> }) >>> = .recipientList(simple("sql:{{sql.lookup}}")).delimiter("false") >>> .to("log:output") >>> .process(new Processor() { >>> public void process(Exchange = exchange) throws Exception { >>> List data =3D = (ArrayList) exchange.getIn().getBody(); >>>=20 >>> // convert data to = response >>>=20 >>> = exchange.getOut().setBody(response); >>> } >>> }) >>>=20 >>> Is it possible to unit test this route and mock the data returned = from the "sql" call? It'd love to be able to verify headers after the = first .process, mock the results from the SQL call and verify the = results from the 2nd .process method. >>>=20 >>> All of the routes I've developed with Camel so far make SQL calls, = but I see SOAP calls in the future. I'll eventually need to mock SOAP = calls as well. >>>=20 >>> Thanks, >>>=20 >>> Matt >>=20 >>=20 >>=20 >> --=20 >> Claus Ibsen >> ----------------- >> Red Hat, Inc. >> Email: cibsen@redhat.com >> Twitter: davsclaus >> Blog: http://davsclaus.com >> Author of Camel in Action: http://www.manning.com/ibsen >> hawtio: http://hawt.io/ >> fabric8: http://fabric8.io/ >=20