Get hold of parameter to mocked object

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

Get hold of parameter to mocked object

by Mattias Jiderhamn-4 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

What is the recommended practice for getting hold of the parameter
passed to a mock object, for further testing.

An example of what I want to do:

  OrderDAO orderDAO = context.mock(OrderDAO.class);
 
  checking(new Expectations() {
      {
        oneOf(orderDAO).save(with(any(Order.class)));
      }
    });

  doSomethingThatCreatesAndSavesOrder();

  Order order = ...; // The order passed to the mocked OrderDAO.save()

  // Regular jUnit tests
  assertEquals("1", order.getCustomer());
  assertEquals(3, order.getNoOfLines());
  ...

I know I can do this using custom matchers:

 ...
  oneOf(orderDAO).save(with(allOf(
      any(Order.class),
      Matchers.hasProperty("customer",
org.hamcrest.CoreMatchers.equalTo("1") // (Need to be declared as local
variable for generics to work)
  )));
 ...

but if the test fails, the error does not include the specific test that
failed but only an "unexpected invocation".

The solution that I have come up with would be to create a Matcher that
remembers the object it is asked to match, which could then be accessed
for further testing.
Seems a bit ugly though. My gut tells me somebody should have thought
about this already.
Is there a better way???

--

  </Mattias>


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

    http://xircles.codehaus.org/manage_email



Re: Get hold of parameter to mocked object

by Chris Miles-5 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Mattias,

In my experience, are you sure thats what you want to be testing for?

You should only be expecting that the DAO's "save" is being invoked with
the order.

Anything further would then be getting tested in the implementation's test
class i.e. "OrderDAOImplTest", and not in this test.

Sorry if I have misunderstood your intentions.

Chris

> What is the recommended practice for getting hold of the parameter
> passed to a mock object, for further testing.
>
> An example of what I want to do:
>
>   OrderDAO orderDAO = context.mock(OrderDAO.class);
>
>   checking(new Expectations() {
>       {
>         oneOf(orderDAO).save(with(any(Order.class)));
>       }
>     });
>
>   doSomethingThatCreatesAndSavesOrder();
>
>   Order order = ...; // The order passed to the mocked OrderDAO.save()
>
>   // Regular jUnit tests
>   assertEquals("1", order.getCustomer());
>   assertEquals(3, order.getNoOfLines());
>   ...
>
> I know I can do this using custom matchers:
>
>  ...
>   oneOf(orderDAO).save(with(allOf(
>       any(Order.class),
>       Matchers.hasProperty("customer",
> org.hamcrest.CoreMatchers.equalTo("1") // (Need to be declared as local
> variable for generics to work)
>   )));
>  ...
>
> but if the test fails, the error does not include the specific test that
> failed but only an "unexpected invocation".
>
> The solution that I have come up with would be to create a Matcher that
> remembers the object it is asked to match, which could then be accessed
> for further testing.
> Seems a bit ugly though. My gut tells me somebody should have thought
> about this already.
> Is there a better way???
>
> --
>
>   </Mattias>
>
>
> ---------------------------------------------------------------------
> 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



Re: Get hold of parameter to mocked object

by Mattias Jiderhamn-4 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I think that is what I want to do.

To put some more details into my example, I want to test business logic.
The output of the business logic is new/updated data, stored via DAOs.
There is no return value or anything else to test on.
Say for example that I want to verify that OrderCreator.createOrder(1,
2, 3) actually does create an order for customer 1 ordering article no.
2 at a quantity of 3.
My plan was to use jMock (since there is a lot of supporting DAO
communication going on in the actual business logic), and after calling
the method I want the test to examine the resulting Order instance which
was passed to the (mocked) OrderDAO by the tested business logic.

Is this not the way to go?
Do I need to create a dummy implementation of the DAO instead, that does
assertions in its save() implementation???

(I agree that the test of the DAO implementation is a totally different
matter)

  </Mattias>


chris@... wrote (2009-08-06 14:51):

> Mattias,
>
> In my experience, are you sure thats what you want to be testing for?
>
> You should only be expecting that the DAO's "save" is being invoked with
> the order.
>
> Anything further would then be getting tested in the implementation's test
> class i.e. "OrderDAOImplTest", and not in this test.
>
> Sorry if I have misunderstood your intentions.
>
> Chris
>
>  
>> What is the recommended practice for getting hold of the parameter
>> passed to a mock object, for further testing.
>>
>> An example of what I want to do:
>>
>>   OrderDAO orderDAO = context.mock(OrderDAO.class);
>>
>>   checking(new Expectations() {
>>       {
>>         oneOf(orderDAO).save(with(any(Order.class)));
>>       }
>>     });
>>
>>   doSomethingThatCreatesAndSavesOrder();
>>
>>   Order order = ...; // The order passed to the mocked OrderDAO.save()
>>
>>   // Regular jUnit tests
>>   assertEquals("1", order.getCustomer());
>>   assertEquals(3, order.getNoOfLines());
>>   ...
>>
>> I know I can do this using custom matchers:
>>
>>  ...
>>   oneOf(orderDAO).save(with(allOf(
>>       any(Order.class),
>>       Matchers.hasProperty("customer",
>> org.hamcrest.CoreMatchers.equalTo("1") // (Need to be declared as local
>> variable for generics to work)
>>   )));
>>  ...
>>
>> but if the test fails, the error does not include the specific test that
>> failed but only an "unexpected invocation".
>>
>> The solution that I have come up with would be to create a Matcher that
>> remembers the object it is asked to match, which could then be accessed
>> for further testing.
>> Seems a bit ugly though. My gut tells me somebody should have thought
>> about this already.
>> Is there a better way???
>>
>> --
>>
>>   </Mattias>
>>    


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

    http://xircles.codehaus.org/manage_email



Re: Get hold of parameter to mocked object

by Julian Hall-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Mattias Jiderhamn wrote:

> What is the recommended practice for getting hold of the parameter
> passed to a mock object, for further testing.
>
> An example of what I want to do:
>
>   OrderDAO orderDAO = context.mock(OrderDAO.class);
>  
>   checking(new Expectations() {
>       {
>         oneOf(orderDAO).save(with(any(Order.class)));
>       }
>     });
>
>   doSomethingThatCreatesAndSavesOrder();
>
>   Order order = ...; // The order passed to the mocked OrderDAO.save()
>
>   // Regular jUnit tests
>   assertEquals("1", order.getCustomer());
>   assertEquals(3, order.getNoOfLines());
>   ...
>
> I know I can do this using custom matchers:
>
>  ...
>   oneOf(orderDAO).save(with(allOf(
>       any(Order.class),
>       Matchers.hasProperty("customer",
> org.hamcrest.CoreMatchers.equalTo("1") // (Need to be declared as local
> variable for generics to work)
>   )));
>  ...
>
> but if the test fails, the error does not include the specific test that
> failed but only an "unexpected invocation".
>
> The solution that I have come up with would be to create a Matcher that
> remembers the object it is asked to match, which could then be accessed
> for further testing.
> Seems a bit ugly though. My gut tells me somebody should have thought
> about this already.
> Is there a better way???
>  
I think doing it via an action is cleaner.  See
http://thread.gmane.org/gmane.comp.java.jmock.user/2278/focus=2284 for
my class that does this.

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

    http://xircles.codehaus.org/manage_email



Re: Get hold of parameter to mocked object

by Chris Miles-5 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Mattias,

I think I understand what you mean.

This is just my opinion, but from my personal learning experience, if a
piece of behaviour is not easily testable, it probably means the code
needs to be refactored. This is what TDD excels at forcing you to.
refactoring possible poor design.

To me, because this is not easily testable it highlights that your
business logic should not be interested in checking that the values of
domain objects are correct.

Your method should probably just be:

OrderCreator.createOrder(order);

and then assert that the order creates calls save on the DAO.

Setting the values of your domain object POJO (order) should probably be
done in a much higher level such as a Struts action, or Servlet.

And when you test your DAO you can test

1. That all the values nessessary in the domain object have been set to
legal/acceptable values.

or

2. That exceptions from your persistance framework are correctly handled
if a POJO is passed with illegal values.

Thats the kinda way we do it in here.

Chris

> I think that is what I want to do.
>
> To put some more details into my example, I want to test business logic.
> The output of the business logic is new/updated data, stored via DAOs.
> There is no return value or anything else to test on.
> Say for example that I want to verify that OrderCreator.createOrder(1,
> 2, 3) actually does create an order for customer 1 ordering article no.
> 2 at a quantity of 3.
> My plan was to use jMock (since there is a lot of supporting DAO
> communication going on in the actual business logic), and after calling
> the method I want the test to examine the resulting Order instance which
> was passed to the (mocked) OrderDAO by the tested business logic.
>
> Is this not the way to go?
> Do I need to create a dummy implementation of the DAO instead, that does
> assertions in its save() implementation???
>
> (I agree that the test of the DAO implementation is a totally different
> matter)
>
>   </Mattias>
>
>
> chris@... wrote (2009-08-06 14:51):
>> Mattias,
>>
>> In my experience, are you sure thats what you want to be testing for?
>>
>> You should only be expecting that the DAO's "save" is being invoked with
>> the order.
>>
>> Anything further would then be getting tested in the implementation's
>> test
>> class i.e. "OrderDAOImplTest", and not in this test.
>>
>> Sorry if I have misunderstood your intentions.
>>
>> Chris
>>
>>
>>> What is the recommended practice for getting hold of the parameter
>>> passed to a mock object, for further testing.
>>>
>>> An example of what I want to do:
>>>
>>>   OrderDAO orderDAO = context.mock(OrderDAO.class);
>>>
>>>   checking(new Expectations() {
>>>       {
>>>         oneOf(orderDAO).save(with(any(Order.class)));
>>>       }
>>>     });
>>>
>>>   doSomethingThatCreatesAndSavesOrder();
>>>
>>>   Order order = ...; // The order passed to the mocked OrderDAO.save()
>>>
>>>   // Regular jUnit tests
>>>   assertEquals("1", order.getCustomer());
>>>   assertEquals(3, order.getNoOfLines());
>>>   ...
>>>
>>> I know I can do this using custom matchers:
>>>
>>>  ...
>>>   oneOf(orderDAO).save(with(allOf(
>>>       any(Order.class),
>>>       Matchers.hasProperty("customer",
>>> org.hamcrest.CoreMatchers.equalTo("1") // (Need to be declared as local
>>> variable for generics to work)
>>>   )));
>>>  ...
>>>
>>> but if the test fails, the error does not include the specific test
>>> that
>>> failed but only an "unexpected invocation".
>>>
>>> The solution that I have come up with would be to create a Matcher that
>>> remembers the object it is asked to match, which could then be accessed
>>> for further testing.
>>> Seems a bit ugly though. My gut tells me somebody should have thought
>>> about this already.
>>> Is there a better way???
>>>
>>> --
>>>
>>>   </Mattias>
>>>
>
>
> ---------------------------------------------------------------------
> 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



Re: Get hold of parameter to mocked object

by Steve Freeman-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On 6 Aug 2009, at 14:20, Julian Hall wrote:

> Mattias Jiderhamn wrote:
>> The solution that I have come up with would be to create a Matcher  
>> that
>> remembers the object it is asked to match, which could then be  
>> accessed
>> for further testing.
>> Seems a bit ugly though. My gut tells me somebody should have thought
>> about this already.
>> Is there a better way???
>>
> I think doing it via an action is cleaner.  See http://thread.gmane.org/gmane.comp.java.jmock.user/2278/focus=2284 
>  for my class that does this.


If you want to stash a parameter, then an Action is the place to do  
it--but it's almost certainly the wrong thing to do.

S

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: Get hold of parameter to mocked object

by Steve Freeman-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Are you working with the most recent version of jMock?

There's new functionality to show where an expectation mismatched, not  
just that it failed. You can extend a FeatureMatcher to extract  
individual details from the object being matched (look in the code for  
examples).

Hanging on to a parameter for checking goes against the grain of  
jMock's approach. If you must, then use an Action, but you probably  
shouldn't.

S.

On 6 Aug 2009, at 13:37, Mattias Jiderhamn wrote:

>  oneOf(orderDAO).save(with(allOf(
>      any(Order.class),
>      Matchers.hasProperty("customer",
> org.hamcrest.CoreMatchers.equalTo("1") // (Need to be declared as  
> local
> variable for generics to work)
>  )));
> ...
>
> but if the test fails, the error does not include the specific test  
> that
> failed but only an "unexpected invocation".
>
> The solution that I have come up with would be to create a Matcher  
> that
> remembers the object it is asked to match, which could then be  
> accessed
> for further testing.
> Seems a bit ugly though. My gut tells me somebody should have thought
> about this already.
> Is there a better way???

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: Get hold of parameter to mocked object

by Andy Law :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Steve Freeman-2 wrote:
There's new functionality to show where an expectation mismatched, not  
just that it failed. You can extend a FeatureMatcher to extract  
individual details from the object being matched (look in the code for  
examples).
Apologies for the late arrival to this thread.

I (think that I) have a similar requirement to the OP.

My DAO (using iBatis) is expected to call a routine on a sqlMapClient object (mocked) when triggered to do so. It passes two arguments. The first is a simple string. The second is a Map<String, Object>. I need to check that the Map that is passed in contains two other objects that were originally supplied to the DAO under test.

e.g.

instance.triggerEvent( object1, object2);

should give me an expectation as follows

one(sqlmc).hitRoutine(with(equals("abc")), with(a(Map.class)));

and the Map passed as the second argument *should* contain object1 under the key "object1" and object2 under the key "object2"


Is this extended FeatureMatcher referred to above the only way to test that the DAO is constructing the second argument correctly?


Later,

Andy

Re: Get hold of parameter to mocked object

by Steve Freeman-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On 11 Sep 2009, at 11:25, Andy Law wrote:

> Apologies for the late arrival to this thread.
>
> I (think that I) have a similar requirement to the OP.e.g.
>
> instance.triggerEvent( object1, object2);
>
> should give me an expectation as follows
>
> one(sqlmc).hitRoutine(with(equals("abc")), with(a(Map.class)));
>
> and the Map passed as the second argument *should* contain object1  
> under the
> key "object1" and object2 under the key "object2"

you can try:

one(sqlmc).hitRouting(with(equalTo("abc")),
                       with(allOf(hasEntry("object1", object1),  
hasEntry("object2", object2))));

S.


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: Get hold of parameter to mocked object

by Andy Law :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Steve Freeman-2 wrote:
On 11 Sep 2009, at 11:25, Andy Law wrote:

<snip />

> and the Map passed as the second argument *should* contain object1  
> under the
> key "object1" and object2 under the key "object2"

you can try:

one(sqlmc).hitRouting(with(equalTo("abc")),
                       with(allOf(hasEntry("object1", object1),  
hasEntry("object2", object2))));

<snip />
Thanks for that suggestion Steve.

In fact, since I posted I wrote a new Matcher that does the job nicely. I coded it as 'aMapThatMatches()' which makes the test code nicely readable

one.(sqlmc).hitRoutine(with(equalTo("abc")), with(aMapThatMatches(templateMap)));

I'm happy to share/contribute this with others. Does it hold any interest for the JMock/Hamcrest devs?

Later,

Andy

Re: Get hold of parameter to mocked object

by Steve Freeman-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

> Thanks for that suggestion Steve.
>
> In fact, since I posted I wrote a new Matcher that does the job  
> nicely. I
> coded it as 'aMapThatMatches()' which makes the test code nicely  
> readable
>
> one.(sqlmc).hitRoutine(with(equalTo("abc")),
> with(aMapThatMatches(templateMap)));
>
> I'm happy to share/contribute this with others. Does it hold any  
> interest
> for the JMock/Hamcrest devs?
>
> Later,

to clarify. aMapThatMatches(templateMap) checks that the actual map  
has the same entries as the templateMap, or does it do something else?

S.


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

    http://xircles.codehaus.org/manage_email



Re: Get hold of parameter to mocked object

by Andy Law :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


Steve Freeman-2 wrote:
to clarify. aMapThatMatches(templateMap) checks that the actual map  
has the same entries as the templateMap, or does it do something else?
You supply a template Map that has the key/value pairs that are expected. The Matcher checks that the argument/actual Map contains each of those key/value pairs. The argument may contain other entries too in the current incarnation. If/when I reach a point that I need an *exact* comparison then I'll add that in somewhere (aMapThatExactlyMatches()??)

So, if template === ( "a" => "a string", "user" = USEROBJECT)

then an argument that looks like ( "a" => "a string", "user" = USEROBJECT, "somethingelse" => 42) will pass.

Later,

Andy