Aaron Rustad | 3 Sep 2007 22:28

First JMock test...how can I improve it?


I started using JMock today, and it seems very promising. However, the  seems a *little* tdocumentationhin, and I was hoping that someone might be able to help me improve my first unit test. It works correctly and gives me the results I am expecting, but I have to admit, it's very smelly. If anyone can offer improvements on the following test case, I would greatly appreciate it!

Thanks!

public class OMSInboundMsgAdaptorImplITC extends MockObjectTestCase {
        Mockery context;
        Gateway gateway;
        OMSInboundMsgAdaptorImpl adaptor;
       
        <at> Override
        protected void setUp() throws Exception {
                context = new Mockery();
                gateway = context.mock(Gateway.class);
                adaptor = new OMSInboundMsgAdaptorImpl(gateway, null);
        }
       
        public void testOnNewOrderSingle() throws Exception {
                SingleOrderMessage singleOrderMessage = new SingleOrderMessage();
                MessageWrapperFactory factory = MessageWrapperFactory.instance(singleOrderMessage);
                               
                final MessageWrapper wrapper = factory.wrap(singleOrderMessage);
                wrapper.setSide(Constants.SIDE_Sell.charAt(0));

                context.checking(new Expectations() {
                        { one(gateway).getNextExecutionIDString((String)with(a(String.class)));};
                        { one(gateway).sendToOMS((MessageWrapper)
                                        with(AllOf.allOf(
                                                        a(MessageWrapper.class),
                                                        HasPropertyWithValue.hasProperty("execTypeRejected", IsEqual.equalTo(true) ))));};
                });
               
                adaptor.onNewOrderSingle(wrapper);
               
                context.assertIsSatisfied();
        }

Nat Pryce | 3 Sep 2007 23:28
Picon

Re: First JMock test...how can I improve it?

On 03/09/07, Aaron Rustad <aaron.rustad@...> wrote:
> I started using JMock today, and it seems very promising. However, the
> seems a *little* tdocumentationhin, and I was hoping that someone might be
> able to help me improve my first unit test. It works correctly and gives me
> the results I am expecting, but I have to admit, it's very smelly. If anyone
> can offer improvements on the following test case, I would greatly
> appreciate it!
>
>  Thanks!

No problem.

Firstly, you don't need need to create a Mockery if you are extending
MockObjectTestCase.  The MockObjectTestCase class does that for you.

Then, you can just call mock(...) to create mock objects and
checking(...) to define expectations.  You don't need to call
mock(...) in setUp.  It's easier (and easier to read) if you call it
in the instance variable declaration itself.

Also, you don't have to put curly brackets around every statement
within the expectations block.  Just start and stop the expectations
with double-curly-brackets.

Using static imports for factory functions (allOf, etc.) makes the
tests much easier to read.  Helper factory-functions also help make
the tests readable and work around limitations in the Java 5 type
system.

Give the test method a name that describes what behaviour is being
tested, not what object and method are being tested.  The object and
method under test are obvious from the code.  Why they are being
tested is not, so the test name needs to add a lot of context to help
the reader.

Avoid expecting getters where possible to avoid brittle tests.  Use
'allowing' rather than 'one'.

I prefer to create new Matchers than use the hasProperty matcher to
make the code easier to refactor.

Finally, you don't need to call context.assertIsSatisfied.  The
MockObjectTestCase class does that for you.

E.g.

public class OMSInboundMsgAdaptorImplITC extends MockObjectTestCase {
    Gateway gateway = mock(Gateway.class);
    OMSInboundMsgAdaptorImpl adaptor =
    new OMSInboundMsgAdaptorImpl(gateway, null);

     public void testRejectsSingleOrderMessageForSomeReason()
         throws Exception
    {
         SingleOrderMessage singleOrderMessage = new SingleOrderMessage();
         MessageWrapperFactory factory =
             MessageWrapperFactory.instance(singleOrderMessage);

         final MessageWrapper wrapper = factory.wrap(singleOrderMessage);
         wrapper.setSide(Constants.SIDE_Sell.charAt(0));

         context.checking(new Expectations() {{
             allowing (gateway).getNextExecutionIDString(with(anyString()));
             one (gateway).sendToOMS(aRejectedMessage());
         }});

         adaptor.onNewOrderSingle(wrapper);
    }

    private Matcher<String> anyString() {
        return any(String.class);
    }

    private Matcher<MessageWrapper> aRejectedMessage() {
        return new RejectedMessageMatcher();
    }

    ...

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

    http://xircles.codehaus.org/manage_email

Aaron Rustad | 4 Sep 2007 19:48

Ignoring most of the methods in a mock....

I have a mock object that has it’s methods called throughout the lifetime of the test. However, I really only care about one specific method gets called. Is there a way I can suppress testing for all method called with the exception of one? For example, if I have this which works fine, :

 

checking(new Expectations() {

                                    { one(gateway).getNextExecutionIDString(with(anyString()));

                                      … many more calls to gateway methods which I don’t care about testing

                                      one(gateway).sendToOMS(with(aRejectedMessage("OrderQty(38)")));};

});

 

However, I would rather the code look something like this (which doesn’t seem to work) :

 

checking(new Expectations() {

                                    { ignoring(gateway);   // IGNORE ALL METHOD CALLS

                                      one(gateway).sendToOMS(with(aRejectedMessage("OrderQty(38)")));};  // WITH THE EXCEPTION OF THIS ONE

});

 

Thanks for your advice!

Aaron.

Takeshi Martinez | 5 Sep 2007 00:19
Picon
Favicon

State change side effect after a throw exception action

Hi!

Would this be a valid use of JMock (2.x) ?

interface Queue {
  void push(Object iItem) throws QueueFullException, OverloadedException;
  Object pull() throws OverloadedException;
  void resetOverload();
}

...

queue = context.mock(Queue.class);

context.checking(new Expectations(){{

   States queueState = context.states("queueState").startsAs("empty");

   one(queue).push(with(any(Object.class)));
      when(queueState.is("empty"));
      then(queueState.is("one"));

   one(queue).push(with(any(Object.class)));
      when(queueState.is("one"));
      then(queueState.is("full"));

   one(queue).push(with(any(Object.class)));
      when(queueState.is("full"));
      will(throwException(new QueueFullException()));
      then(queueState.is("overloaded"));

   one(queue).push(with(any(Object.class)));
      when(queueState.is("overloaded"));
      will(throwException(new OverloadedException()));

   one(queue).pull();
      when(queueState.is("overloaded"));
      will(throwException(new OverloadedException()));

   one(queue).resetOverload();
      when(queueState.is("overloaded"));
      then(queueState.is("empty"))

   never(queue).resetOverload();
      when(queueState.isNot("overloaded"));

   one(queue).pull();
      when(queueState.is("full"));
      will(returnValue(new Object()));
      then(queueState.is("one"))

   one(queue).pull();
      when(queueState.is("one"));
      will(returnValue(new Object()));
      then(queueState.is("empty"))

   one(queue).pull();
      when(queueState.is("empty"));
      then(queueState.is("empty"))

}});

It is a bit of an over engineered queue of size 2! What I want to highlight is
that on the third push, the queue throws a QueueFullException and *should* go
into overload state, there after the only way to recover is by calling
resetOverload which clears the queue completely.

I find that the third push throws a QueueFullException. Can anyone confirm? Is
this the right way to be using JMock?

Thanks in advance!

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

    http://xircles.codehaus.org/manage_email

Geoffrey Wiseman | 5 Sep 2007 05:24
Picon
Gravatar

Re: Ignoring most of the methods in a mock....

On 9/4/07, Aaron Rustad <aaron.rustad-WhXs6c/e3RAAvxtiuMwx3w@public.gmane.org> wrote:

However, I would rather the code look something like this (which doesn't seem to work) : 

checking(new Expectations() {

                                    { ignoring(gateway);   // IGNORE ALL METHOD CALLS

                                      one(gateway).sendToOMS(with(aRejectedMessage("OrderQty(38)")));};  // WITH THE EXCEPTION OF THIS ONE

});

Order's important here.  Put the call to one() before ignoring(), and  it should be fine.

--
Geoffrey Wiseman
Nat Pryce | 5 Sep 2007 07:48
Picon

Re: State change side effect after a throw exception action

It might be better to divide your test into multiple small tests.
E.g. what does the object under test do when it can successfully push
onto the queue?  What does it do when the test throws
OverloadedException?  And so on.

--Nat

On 04/09/07, Takeshi Martinez <takeshi@...> wrote:
> Hi!
>
> Would this be a valid use of JMock (2.x) ?
>
> interface Queue {
>   void push(Object iItem) throws QueueFullException, OverloadedException;
>   Object pull() throws OverloadedException;
>   void resetOverload();
> }
>
> ...
>
> queue = context.mock(Queue.class);
>
> context.checking(new Expectations(){{
>
>    States queueState = context.states("queueState").startsAs("empty");
>
>
>    one(queue).push(with(any(Object.class)));
>       when(queueState.is("empty"));
>       then(queueState.is("one"));
>
>    one(queue).push(with(any(Object.class)));
>       when(queueState.is("one"));
>       then(queueState.is("full"));
>
>    one(queue).push(with(any(Object.class)));
>       when(queueState.is("full"));
>       will(throwException(new QueueFullException()));
>       then(queueState.is("overloaded"));
>
>    one(queue).push(with(any(Object.class)));
>       when(queueState.is("overloaded"));
>       will(throwException(new OverloadedException()));
>
>    one(queue).pull();
>       when(queueState.is("overloaded"));
>       will(throwException(new OverloadedException()));
>
>    one(queue).resetOverload();
>       when(queueState.is("overloaded"));
>       then(queueState.is("empty"))
>
>    never(queue).resetOverload();
>       when(queueState.isNot("overloaded"));
>
>    one(queue).pull();
>       when(queueState.is("full"));
>       will(returnValue(new Object()));
>       then(queueState.is("one"))
>
>    one(queue).pull();
>       when(queueState.is("one"));
>       will(returnValue(new Object()));
>       then(queueState.is("empty"))
>
>    one(queue).pull();
>       when(queueState.is("empty"));
>       then(queueState.is("empty"))
>
> }});
>
> It is a bit of an over engineered queue of size 2! What I want to highlight is
> that on the third push, the queue throws a QueueFullException and *should* go
> into overload state, there after the only way to recover is by calling
> resetOverload which clears the queue completely.
>
> I find that the third push throws a QueueFullException. Can anyone confirm? Is
> this the right way to be using JMock?
>
> Thanks in advance!
>
>
> ---------------------------------------------------------------------
> To unsubscribe from this list please visit:
>
>     http://xircles.codehaus.org/manage_email
>
>

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

    http://xircles.codehaus.org/manage_email

Nat Pryce | 5 Sep 2007 07:58
Picon

Re: Ignoring most of the methods in a mock....

That won't quite work as expected.  It will act as if the sendToOMS
method must be called at least once because after being called once
the 'one' expectation will be inactive but the 'ignoring' expectation
will continue to match and allow calls.

More information at: http://www.jmock.org/dispatch.html

You can solve the problem by adding an additional 'never' expectation:

  one (gateway).sendToOMS(with(aRejectedMessage("OrderQty(38)")));
  never (gateway).sendToOMS(with(anyMessage));
  ignoring (gateway); // ignore all other calls

However, that's rather confusing to read.  Using states makes the
intent of the test much clearer and will produce better error messages
if the code under test fails:

  final States message = context.states("message");

  one (gateway).sendToOMS(with(aRejectedMessage("OrderQty(38)")));
      when(message.isNot("sent"));
      then(message.is("sent"));
  never (gateway).sendToOMS(with(anyMessage));
      when(message.is("sent"));
  ignoring (gateway); // ignore all other calls

--Nat

On 05/09/07, Geoffrey Wiseman <geoffrey.wiseman@...> wrote:
> On 9/4/07, Aaron Rustad <aaron.rustad@...> wrote:
> >
> >
> > However, I would rather the code look something like this (which doesn't
> seem to work) :
> >
> > checking(new Expectations() {
> >
> >                                     { ignoring(gateway);
>  // IGNORE ALL METHOD CALLS
> >
> >
> one(gateway).sendToOMS(with(aRejectedMessage("OrderQty(38)")));};
>  // WITH THE EXCEPTION OF THIS ONE
> >
> > });
> Order's important here.  Put the call to one() before ignoring(), and  it
> should be fine.
>
> --
> Geoffrey Wiseman
>

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

    http://xircles.codehaus.org/manage_email

Rakesh Ranjan | 5 Sep 2007 15:39

help needed for jms test cases

Hi,

I am a novice user of JMock. I am writing some test cases for jms
messages.

I created mock of javax.jms.BytesMessage.

The BytesMessage class has a methode called readBytes that accept a byte
array. It accepts a byte array as an argument. The execution of this
method fill the array with the body content of the byte message and
return the length of the content of the message.
	
I am doing it this way.

final Mock mockJMSMsg = mock(BytesMessage.class);
mockJMSMsg.stubs().method("readBytes").will(returnValue(1024));

Obviously it wouldn't work. The above is returning the length of array
that is 1024, but this method should also fill the byte array passed as
argument with the content of the message. I don't know how to achieve
the functionality of readBytes method.

Can you please provide me some sample example?

Thank and Regards,
Ranjan

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

    http://xircles.codehaus.org/manage_email

Dale King | 5 Sep 2007 15:53
Picon

Re: help needed for jms test cases

I think you would have to create your own CustomAction to have it write into passed parameter and return the amount of data that was written.

But it seems to me that BytesMessage is not really something you would need to be mocking, but it depends on what it is you are testing. Nat would tell you to never mock a class you don't own, but I don't agree with that.

On 9/5/07, Rakesh Ranjan <rranjan-j7Fd8dkzv11Wk0Htik3J/w@public.gmane.org> wrote:
Hi,

I am a novice user of JMock. I am writing some test cases for jms
messages.

I created mock of javax.jms.BytesMessage.

The BytesMessage class has a methode called readBytes that accept a byte
array. It accepts a byte array as an argument. The execution of this
method fill the array with the body content of the byte message and
return the length of the content of the message.

I am doing it this way.

final Mock mockJMSMsg = mock(BytesMessage.class);
mockJMSMsg.stubs().method("readBytes").will(returnValue(1024));

Obviously it wouldn't work. The above is returning the length of array
that is 1024, but this method should also fill the byte array passed as
argument with the content of the message. I don't know how to achieve
the functionality of readBytes method.

Can you please provide me some sample example?


Thank and Regards,
Ranjan



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

    http://xircles.codehaus.org/manage_email




--
Dale King
Paulin | 5 Sep 2007 19:14
Favicon

MockObjectTestCase Mockery Not Found error

I saw the post "First JMock test...how can I improve it?" and noticed a
statement in there about using MockObjectTestCase.  I liked that better then
having to create the Mockery every time.

Anyway I got it working great yesterday but know I have a bizarre issue.

I have a Global Test Suite that holds all other test suite.

Then I have inidividual test suite.

Then individual test.

I turned JMock into an eclipse plug-in too and set up the buddy sharing.  

So if I run the Global Test Suite things work fine.

If I run the individual tests that extend the MockObjectTestCase I get an error
of  "no Mockery found in test class class com..."

So if I put a mockery in the object (even thought I still included from the
MockObjectTestCase and the mockery is some other name) it will work.

Any thoughts.
steve

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

    http://xircles.codehaus.org/manage_email


Gmane