Expextations return an Object that then mocks a method

View: New views
4 Messages — Rating Filter:   Alert me  

Expextations return an Object that then mocks a method

by quinn :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I am new to JMock and trying to apply it to some JMS code.

Perhaps I have chosen poor design, but I am having a difficult time getting the expectations to function as I understand they should.

In particular, if the method I am testing creates a new object, and then calls a method with the newly created object, how is the situation properly mocked?

Here is the code and trace:
public final class MDItemPublisher implements MDItemPublisherI{
       
        private final static Logger log = AtsLogMgr
                .getInstance(MDItemPublisher.class.getPackage().getName());
       
        // JMS iv's
        private final String topicName;
        private final TopicSession topicSession;
        private final TopicPublisher tpub;

        protected MDItemPublisher(final String topicName, final TopicSession topicSession,
                        final TopicPublisher tpub) {
                this.topicName = topicName;
                this.topicSession = topicSession;
                this.tpub = tpub;
        }
        @Override
        public final void publishMD(final MarketDataQuoteI msg) {
                try {
                        // get ready to publish
                        final ObjectMessage omsg = topicSession.createObjectMessage();
                        // set object message to be sent
                        omsg.setObject(msg);
                        // publish the object message
                        tpub.publish(omsg);
                } catch (JMSException e) {
                        log.warning(e.getMessage());
                }
        }

        @Override
        public void destroy() {
                try {
                        tpub.close();
                } catch (JMSException e) {
                        log.warning(e.getMessage());
                }
        }

        public String toString(){
                StringBuffer sb = new StringBuffer();
                sb.append("MDItemPublisher:" + topicName);
                try {
                        sb.append(" delivery mode " + tpub.getDeliveryMode());
                        sb.append(" priority: " + tpub.getPriority());
                        sb.append(" ttl: " + tpub.getTimeToLive());
                        sb.append(" destination: " + tpub.getDestination());
                } catch (JMSException e) {
                        log.warning(e.getMessage());
                }
                return sb.toString();
        }

}

public class MDItemPublisherTest {

        private static Mockery context = new JUnit4Mockery();
        @Test
        public final void testMDItemPublisher() {
                String topicName = "testTopicName";
                TopicSession ts = context.mock(TopicSession.class);
                TopicPublisher tpub = context.mock(TopicPublisher.class);
                //execute
                MDItemPublisher underTest = new MDItemPublisher(topicName, ts, tpub);
                //verify
                assertTrue(underTest instanceof MDItemPublisher);
                context.assertIsSatisfied();
        }

        @Test
        public final void testPublishMD() throws JMSException {
                String topicName = "testTopicName";
                final TopicSession ts2 = context.mock(TopicSession.class, "ts2");
                final TopicPublisher tpub2 = context.mock(TopicPublisher.class, "tpub2");
                final ObjectMessage om = context.mock(ObjectMessage.class);
               
               
                MDItemPublisher underTest = new MDItemPublisher(topicName, ts2, tpub2);
                final MarketDataQuoteI testQuote = context.mock(MarketDataQuoteI.class);
               
                context.checking(new Expectations() {{
                                one(ts2).createObjectMessage(testQuote);
                                                     will(returnValue(a(ObjectMessage.class)));
                                one (om).setObject(testQuote);
                                one (tpub2).publish((Message) testQuote);
                        }});
                //execute
                underTest.publishMD(testQuote);
               
                //verify
                context.assertIsSatisfied();
        }

        @Test
        public final void testDestroy() {
                fail("Not yet implemented"); // TODO
        }

}

trace:
java.lang.ClassCastException: $Proxy7
        at com.ats.bus.md.pub.MDItemPublisherTest$1.<init>(MDItemPublisherTest.java:54)
        at com.ats.bus.md.pub.MDItemPublisherTest.testPublishMD(MDItemPublisherTest.java:51)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:59)
        at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:98)
        at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79)
        at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:87)
        at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77)
        at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42)
        at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:88)
        at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
        at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
        at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
        at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
        at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
        at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
        at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)





Re: Expextations return an Object that then mocks a method

by Steve Freeman-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

The problem is here:

one(ts2).createObjectMessage(testQuote);  
will(returnValue(a(ObjectMessage.class)));

the call is returning the class ObjectMessage, it should return an /
instance/ of an ObjectMessage. You've already mocked
one in the variable 'om'.  My reading of the code is the expectations  
should read:

allowing(ts2).createObjectMessage(testQuote); will(returnValue(om));
one(om).setObject(testQuote);
one(tpub2).publish(om);

there's an interesting point as to whether you should check that the  
message contents has been set before publishing, but that can wait.

Further points:
- if you annotate your class with @RunWith(JMock.class); you don't  
have to explicitly call assertIsSatisfied();
- what is the first test for? It doesn't seem to assert anything more  
than the type system does.

On 16 Aug 2009, at 01:15, quinn wrote:
> I am new to JMock and trying to apply it to some JMS code.
> [...]

Steve Freeman
Winner of the Agile Alliance Gordon Pask award 2006

http://www.m3p.co.uk

M3P Limited.
Registered office. 2 Church Street, Burnham, Bucks, SL1 7HZ.
Company registered in England & Wales. Number 03689627



---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email



Re: Expextations return an Object that then mocks a method

by quinn :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Thanks for the quick reply and suggestions.

So my interpretation is that when I call a mock method that creates an object, I should specify the expectation of what will be returned, but also create what is returned if it is used consequently.

One question I have is why you would use "allowing" instead of "one". Is it because the code is inside a try clause? Is there a place to find a lot of expectation examples? I seem to be having a problem understanding the semantics.

As for the first test, I see your point and will delete it.MarketDataQuoteI.javaMDItemPublisher.javaMDItemPublisherTest.java

Unfortunately, your suggestion for the second test does not seem to fix the problem. Here is the trace.

java.lang.AssertionError: unexpected invocation: ts2.createObjectMessage()
expectations:
  allowed, never invoked: ts2.createObjectMessage(<marketDataQuoteI>); returns <objectMessage>
  expected exactly 1 time, never invoked: objectMessage.setObject(<marketDataQuoteI>); returns a default value
  expected exactly 1 time, never invoked: tpub2.publish(<objectMessage>); returns a default value
        at org.jmock.internal.InvocationDispatcher.dispatch(InvocationDispatcher.java:56)
        at org.jmock.Mockery.dispatch(Mockery.java:204)
        at org.jmock.Mockery.access$000(Mockery.java:37)
        at org.jmock.Mockery$MockObject.invoke(Mockery.java:246)
        at org.jmock.internal.InvocationDiverter.invoke(InvocationDiverter.java:27)
        at org.jmock.internal.ProxiedObjectIdentity.invoke(ProxiedObjectIdentity.java:36)
        at org.jmock.lib.JavaReflectionImposteriser$1.invoke(JavaReflectionImposteriser.java:33)
        at $Proxy6.createObjectMessage(Unknown Source)
        at com.ats.bus.md.pub.MDItemPublisher.publishMD(MDItemPublisher.java:33)
        at com.ats.bus.md.pub.MDItemPublisherTest.testPublishMD(MDItemPublisherTest.java:53)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:59)
        at org.jmock.integration.junit4.JMock$1.invoke(JMock.java:36)
        at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:98)
        at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79)
        at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:87)
        at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77)
        at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42)
        at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:88)
        at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
        at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
        at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
        at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
        at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
        at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
        at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)


Steve Freeman-2 wrote:
The problem is here:

one(ts2).createObjectMessage(testQuote);  
will(returnValue(a(ObjectMessage.class)));

the call is returning the class ObjectMessage, it should return an /
instance/ of an ObjectMessage. You've already mocked
one in the variable 'om'.  My reading of the code is the expectations  
should read:

allowing(ts2).createObjectMessage(testQuote); will(returnValue(om));
one(om).setObject(testQuote);
one(tpub2).publish(om);

there's an interesting point as to whether you should check that the  
message contents has been set before publishing, but that can wait.

Further points:
- if you annotate your class with @RunWith(JMock.class); you don't  
have to explicitly call assertIsSatisfied();
- what is the first test for? It doesn't seem to assert anything more  
than the type system does.

On 16 Aug 2009, at 01:15, quinn wrote:
> I am new to JMock and trying to apply it to some JMS code.
> [...]

Steve Freeman
Winner of the Agile Alliance Gordon Pask award 2006

http://www.m3p.co.uk

M3P Limited.
Registered office. 2 Church Street, Burnham, Bucks, SL1 7HZ.
Company registered in England & Wales. Number 03689627



---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Re: Expextations return an Object that then mocks a method

by Nat Pryce :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

What that us telling you is that yiur code is calling
"createObjectMessage()" (note: no parameters) but that call is not
expected.

What you have expected is both createObjectMessage with an object
argument *and* setObject on the message that is returned. In JMS you
usually do one or the other: create an object message (with no
parameter) and then set the message's object, or create an object
message for an object in one call. Pick either of those approaches and
make your expectations consistent and the test will pass (or at least
get a little further).

A word of warning, however: JMS is not an API that lends itself to
mocking. It's extremely awkward to do simple things in JMS and many if
the interfaces are either factories or bags of properties. Setting up
the. Expectations is arduous and makes your tests hard to read.
Normally that can be taken as feedback about the design: if you change
the design to make it easier to write tests you will improve the
design and make the software easier to maintain. However, JMS is a
standard API so you can't change it in response to that feedback.

Therefore I usually use mock objects to drive out the API of an
adapter layer between my objects and JMS and write integration tests
to test the implementation of that API. I do the same with most
third-party libraries.

--Nat

On Sunday, August 16, 2009, quinn <quinn.tf@...> wrote:

>
> Thanks for the quick reply and suggestions.
>
> So my interpretation is that when I call a mock method that creates an
> object, I should specify the expectation of what will be returned, but also
> create what is returned if it is used consequently.
>
> One question I have is why you would use "allowing" instead of "one". Is it
> because the code is inside a try clause? Is there a place to find a lot of
> expectation examples? I seem to be having a problem understanding the
> semantics.
>
> As for the first test, I see your point and will delete it.
> http://www.nabble.com/file/p24995890/MarketDataQuoteI.java
> MarketDataQuoteI.java
> http://www.nabble.com/file/p24995890/MDItemPublisher.java
> MDItemPublisher.java
> http://www.nabble.com/file/p24995890/MDItemPublisherTest.java
> MDItemPublisherTest.java
>
> Unfortunately, your suggestion for the second test does not seem to fix the
> problem. Here is the trace.
>
> java.lang.AssertionError: unexpected invocation: ts2.createObjectMessage()
> expectations:
>   allowed, never invoked: ts2.createObjectMessage(<marketDataQuoteI>);
> returns <objectMessage>
>   expected exactly 1 time, never invoked:
> objectMessage.setObject(<marketDataQuoteI>); returns a default value
>   expected exactly 1 time, never invoked: tpub2.publish(<objectMessage>);
> returns a default value
>         at
> org.jmock.internal.InvocationDispatcher.dispatch(InvocationDispatcher.java:56)
>         at org.jmock.Mockery.dispatch(Mockery.java:204)
>         at org.jmock.Mockery.access$000(Mockery.java:37)
>         at org.jmock.Mockery$MockObject.invoke(Mockery.java:246)
>         at org.jmock.internal.InvocationDiverter.invoke(InvocationDiverter.java:27)
>         at
> org.jmock.internal.ProxiedObjectIdentity.invoke(ProxiedObjectIdentity.java:36)
>         at
> org.jmock.lib.JavaReflectionImposteriser$1.invoke(JavaReflectionImposteriser.java:33)
>         at $Proxy6.createObjectMessage(Unknown Source)
>         at com.ats.bus.md.pub.MDItemPublisher.publishMD(MDItemPublisher.java:33)
>         at
> com.ats.bus.md.pub.MDItemPublisherTest.testPublishMD(MDItemPublisherTest.java:53)
>         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>         at
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
>         at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
>         at java.lang.reflect.Method.invoke(Method.java:597)
>         at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:59)
>         at org.jmock.integration.junit4.JMock$1.invoke(JMock.java:36)
>         at
> org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:98)
>         at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79)
>         at
> org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:87)
>         at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77)
>         at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42)
>         at
> org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:88)
>         at
> org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
>         at
> org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
>         at
> org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
>         at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
>         at
> org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
>         at
> org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
>         at
> org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
>         at
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
>         at
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
>         at
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
>         at
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
>
>
>
> Steve Freeman-2 wrote:
>>
>> The problem is here:
>>
>> one(ts2).createObjectMessage(testQuote);
>> will(returnValue(a(ObjectMessage.class)));
>>
>> the call is returning the class ObjectMessage, it should return an /
>> instance/ of an ObjectMessage. You've already mocked
>> one in the variable 'om'.  My reading of the code is the expectations
>> should read:
>>
>> allowing(ts2).createObjectMessage(testQuote); will(returnValue(om));
>> one(om).setObject(testQuote);
>> one(tpub2).publish(om);
>>
>> there's an interesting point as to whether you should check that the
>> message contents has been set before publishing, but that can wait.
>>
>> Further points:
>> - if you annotate your class with @RunWith(JMock.class); you don't
>> have to explicitly call assertIsSatisfied();
>> - what is the first test for? It doesn't seem to assert anything more
>> than the type system does.
>>
>> On 16 Aug 2009, at 01:15, quinn wrote:
>>> I am new to JMock and trying to apply it to some JMS code.
>>> [...]
>>
>> Steve Freeman
>> Winner of the Agile Alliance Gordon Pask award 2006
>>
>> http://www.m3p.co.uk
>>
>> M3P Limited.
>> Registered office. 2 Church Street, Burnham, Bucks, SL1 7HZ.
>> Company registered in England & Wales. Number 03689627
>>
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe from this list, please visit:
>>
>>     http://xircles.codehaus.org/manage_email
>>
>>
>>
>>
>
> --
> View this message in context: http://www.nabble.com/Expextations-return-an-Object-that-then-mocks-a-method-tp24989274p24995890.html
> Sent from the jMock - User mailing list archive at Nabble.com.
>
>
> ---------------------------------------------------------------------
> To unsubscribe from this list, please visit:
>
>     http://xircles.codehaus.org/manage_email
>
>
>

--
http://www.natpryce.com

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email