Return-Path: list-help: list-unsubscribe: List-Post: List-Id: Mailing-List: contact cactus-user-help@jakarta.apache.org; run by ezmlm Delivered-To: mailing list cactus-user@jakarta.apache.org Received: (qmail 51237 invoked by uid 98); 25 May 2004 17:58:06 -0000 Received: from jbrains@rogers.com by hermes.apache.org by uid 82 with qmail-scanner-1.20 (clamuko: 0.70. Clear:RC:0(66.185.86.74):. Processed in 0.063653 secs); 25 May 2004 17:58:06 -0000 X-Qmail-Scanner-Mail-From: jbrains@rogers.com via hermes.apache.org X-Qmail-Scanner: 1.20 (Clear:RC:0(66.185.86.74):. Processed in 0.063653 secs) Received: from unknown (HELO fep04-mail.bloor.is.net.cable.rogers.com) (66.185.86.74) by hermes.apache.org with SMTP; 25 May 2004 17:58:06 -0000 Received: from [192.168.1.112] ([24.156.43.226]) by fep04-mail.bloor.is.net.cable.rogers.com (InterMail vM.5.01.05.12 201-253-122-126-112-20020820) with ESMTP id <20040525175543.MFHF456352.fep04-mail.bloor.is.net.cable.rogers.com@[192.168.1.112]> for ; Tue, 25 May 2004 13:55:43 -0400 Message-ID: <40B38938.1040306@rogers.com> Date: Tue, 25 May 2004 13:58:16 -0400 From: "J. B. Rainsberger" User-Agent: Mozilla Thunderbird 0.6 (Windows/20040502) X-Accept-Language: en-us, en MIME-Version: 1.0 To: Cactus Users List Subject: Testing a MDB on its own References: In-Reply-To: Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit X-Authentication-Info: Submitted using SMTP AUTH PLAIN at fep04-mail.bloor.is.net.cable.rogers.com from [24.156.43.226] using ID at Tue, 25 May 2004 13:55:43 -0400 X-Spam-Rating: hermes.apache.org 1.6.2 0/1000/N Jayaraman.Dorai@transplace.com wrote: > I am not sure I understood the solution completely, let me explain my > problem again. May be I should read the books suggested. > > There are 3 components a) the MDB (lets say MDB1) which I want to test, b) > the session ejb, and c) another MDB (lets say MDB2) which the session > ejb calls. > > Now, if I call the extracted method in the MDB1 directly, it will make a > further call to session ejb which in turns asynchronously calls MDB2. Both > session ejb and MDB2 create records in the database. Now I want to test > that the records are being properly created. The testXXX() method will > succeed for only the records created in the session ejb and will fail for > the tests of records created in MDB2 as the MDB2 may not have been > completed. Now I have a situation where MDB1 did not fail but the test > cases shows it has failed. > > Will mock objects or the suggested techniques, help me test the MDB1 > completely? To summarize: MDB1 -> SessionEJB -> MDB2 You define success for MDB1 as "the right records are created in the database." Now, it is possible for MDB1 to succeed, but your success condition not to occur: if, say, MDB2 fails. Do you want your test for MDB1 to fail if only MDB2 fails? I say "no," because then it's not a test for MDB1, but rather an integration test. NOTE: I AM NOT SAYING THAT INTEGRATION TESTS ARE BAD. I /am/ saying that you seem only to want to test MDB1, and so you do not want to write an integration test, as that test might fail even through MDB1 works. THEREFORE, we need to redesign so that MDB1 can run without MDB2. This way we can test MDB1 separately without relying on the correctness of MDB2. NOW, MDB1 uses JNDI to retrieve a component interface for SessionEJB. At some point, MDB1 invokes a method on SessionEJB /which is expected eventually to result in records being created in the database/. I don't know what that method is, but let's say it's doWork(). interface SessionComponent { void doWork() throws Exception; } The idea is that the SessionBean implements doWork() to send a message that you expect MDB2 to handle, leading it then to create records in the database. THEREFORE, ASSUME THAT WHEN YOU INVOKE doWork(), THAT IT WILL CORRECTLY CREATE RECORDS IN THE DATABASE. You're not testing this right now. You're testing whether MDB1 does the right thing, which includes invoking SessionComponent.doWork(). My definition of success is now this: MDB1 should invoke SessionComponent.doWork() exactly once. With mock objects, I can write that test: [pseudocode, similar to jMock] testMdb1 { sessionComponent = create mock for SessionComponent sessionComponent.expect("doWork" invoked 1 time with no parameters, returning nothing) sessionComponent.readyToGo() message = create mock for Message message.expect(whatever methods you need to invoke to retrieve data, returning fake data) message.readyToGo() mdb1 = new MessageDrivenBean1() mdb1.processMessage(message, sessionComponent) sessionComponent.verify() } To make this test pass, I need to redesign MDB1 the way I discussed earlier. [pseudocode] class MessageDrivenBean1 ... { public void onMessage(Message message) { sessionComponent = lookup session EJB with JNDI processMessage(message, sessionComponent) } public void processMessage(Message message, SessionComponent sessionComponent) { do the real work } } Now you don't have to drag JNDI, the database or the EJB container into the test: you can test MDB1 on its own! As far as the JNDI lookup goes, that's still untested, but the majority of the real work /is/ tested, and that's a very good start. Once you're comfortable with this, we can talk about good strategies for testing the JNDI lookup. (Hint: www.mockejb.org) Better? [BTW: This is /almost/ an excerpt from my book, so that gives you an idea what's in there.] -- J. B. Rainsberger, Diaspar Software Services http://www.diasparsoftware.com :: +1 416 791-8603 Let's write software that people understand