Haroon Rafique | 16 Jul 20:37
Favicon

mocking concrete classes with final toString method

Hi there,

I'm using jmock 2.5.0RC1. When trying to mock concrete classes with final 
toString methods, I'm getting:

java.lang.IllegalArgumentException: 
ClassNameHere has a final toString method

Looking through jira and the changelogs, this is a direct result of this 
bug:
 	http://jira.codehaus.org/browse/JMOCK-150
and was implemented in changeset:
 	http://fisheye.codehaus.org/changelog/jmock?cs=1152

Is there a middle ground somewhere? I'm working with 3rd party classes 
where I have no control over their class structure. JMOCK-150 seems like 
squashing a bug with a hammer.

The original bug reporter mentioned that:

 	* an un-expected exception during the assertIsSatisfied() check
           (got the exception when tring to describe the mocked class using
           the final toString() which uses other methods from the original
           class)

Could the code in Mockery.assertIsSatisfied() look for the fact that a 
ClassImposteriser is being used and to bypass the toString method in case 
it is final? pseudo-code follows:

new ExpectationError("not all expectations were satisfied",
(Continue reading)

Nat Pryce | 17 Jul 09:55

Re: mocking concrete classes with final toString method

2008/7/16 Haroon Rafique <haroon.rafique@...>:
> Could the code in Mockery.assertIsSatisfied() look for the fact that a
> ClassImposteriser is being used and to bypass the toString method in case it
> is final?

That's not the problem.

JMock uses the toString method to generate error messages.  If
toString is final, it's implementation will fail when called on a mock
object, because the object will not have been initialised by the
constructor.  So the code that generates the error message will itself
crash, usually with a NullPointerException.

There is some code that is too legacy even for the ClassImposteriser
to deal with, unfortunately.

--Nat

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

    http://xircles.codehaus.org/manage_email

Nat Pryce | 17 Jul 10:02

Re: mocking concrete classes with final toString method

2008/7/17 Nat Pryce <nat.pryce@...>:
> 2008/7/16 Haroon Rafique <haroon.rafique@...>:
>> Could the code in Mockery.assertIsSatisfied() look for the fact that a
>> ClassImposteriser is being used and to bypass the toString method in case it
>> is final?
>
> That's not the problem.
>
> JMock uses the toString method to generate error messages.

More details...

JMock calls toString to describe parameters of expectations or
arguments of Matchers, so calling a final toString method will crash
jMock if the mock object is passed as a parameter of an invocation or
to constrain the parameters of an expectation.  It's not just a case
of a conditional around the code that describes the target of an
invocation.

--Nat

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

    http://xircles.codehaus.org/manage_email

Haroon Rafique | 17 Jul 14:19
Favicon

Re: mocking concrete classes with final toString method

On Today at 9:02am, NP=>Nat Pryce <nat.pryce@...> wrote:

NP> [..snip..]
NP> 
NP> More details...
NP> 
NP> JMock calls toString to describe parameters of expectations or 
NP> arguments of Matchers, so calling a final toString method will crash 
NP> jMock if the mock object is passed as a parameter of an invocation or 
NP> to constrain the parameters of an expectation.  It's not just a case 
NP> of a conditional around the code that describes the target of an 
NP> invocation.
NP> 
NP> --Nat

Ouch. So, in your opinion, is my only option to stay with jmock 1?

Later,
--
Haroon Rafique
<haroon.rafique@...>

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

    http://xircles.codehaus.org/manage_email

Nat Pryce | 17 Jul 15:09

Re: mocking concrete classes with final toString method

2008/7/17 Haroon Rafique <haroon.rafique@...>:
> Ouch. So, in your opinion, is my only option to stay with jmock 1?

JMock 1 has the same problem, only it doesn't detect it when you try
to create the mock object.  You'll just get a confusing crash when
your test fails and no informative diagnostics.

--Nat

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

    http://xircles.codehaus.org/manage_email

Haroon Rafique | 17 Jul 15:33
Favicon

Re: mocking concrete classes with final toString method

On Today at 2:09pm, NP=>Nat Pryce <nat.pryce@...> wrote:

NP> [..snip..]
NP> 
NP> JMock 1 has the same problem, only it doesn't detect it when you try 
NP> to create the mock object.  You'll just get a confusing crash when 
NP> your test fails and no informative diagnostics.
NP> 
NP> --Nat

Hi Nat,

Thanks for continuing this discussion. I want to make sure I understand 
all my options, so please bear with me.

I have tests right now that use concrete mocks of classes which have final 
toString methods and they work fine in jmock1. E.g.:

      service.expects(once())
              .method("getReplyDB2Output")
              .will(returnValue(pda));

where service is a concrete class (not interface) with a final toString 
method. Did I mention it was a 3rd-party class?

If I comment the above expectation out, the test fails and I believe 
jmock1 gives me enough information to correct the error about the 
unexpected invocation. I get:

org.jmock.core.DynamicMockError: mockReplyService: unexpected 
(Continue reading)

Nat Pryce | 17 Jul 16:01

Re: mocking concrete classes with final toString method

2008/7/17 Haroon Rafique <haroon.rafique@...>:
> I have tests right now that use concrete mocks of classes which have final
> toString methods and they work fine in jmock1. E.g.:
>
>      service.expects(once())
>              .method("getReplyDB2Output")
>              .will(returnValue(pda));
>
> where service is a concrete class (not interface) with a final toString
> method. Did I mention it was a 3rd-party class?

What error message does jMock 1 generate if you use service as a
parameter constraint of a failing expectation or pass it as a
parameter of an invocation that causes an expectation to fail?

> So, now you can appreciate why I said that it looks like my only option is
> to stay with jmock1. Staying with jmock1 for ever doesn't sound very
> appealing to me. I know jmock1 and jmock2 are significantly different
> beasts but not having an upgrade path is a little tough to swallow.
>
> I don't know enough about jmock2 source but I'm willing to experiment
> with it if you or anyone else suggests some patches to try.

You can look into writing your own Imposteriser that can imposterise
concrete classes where toString is final.  An implementation would
work just for the scenario you have, and would not support all cases
and will produce confusing error messages in some cases, so cannot go
into jMock core.

However, the problem comes from mocking third-party code that you
(Continue reading)

Haroon Rafique | 18 Jul 15:03
Favicon

Re: mocking concrete classes with final toString method

On Yesterday at 3:01pm, NP=>Nat Pryce <nat.pryce@...> wrote:

NP> [..snip..]
NP> 
NP> You can look into writing your own Imposteriser that can imposterise 
NP> concrete classes where toString is final.  An implementation would 
NP> work just for the scenario you have, and would not support all cases 
NP> and will produce confusing error messages in some cases, so cannot go 
NP> into jMock core.
NP> 

Thanks, Nat. I chose to write an Imposteriser as you suggested above.

BTW, useful advice below. I'll keep that in mind.

The cookbook has a section on upgrading from jmock1 to 2:
http://www.jmock.org/upgrade1to2.html
I think it would be benefitial if it mentioned the lack of .reset() method 
in jmock2. Once I understood that part, the rest of the upgrade was pretty 
painless. Overall, I like the jmock2 syntax.

NP> However, the problem comes from mocking third-party code that you
NP> cannot change.  It's not what we recommend jMock for because you
NP> cannot change the code in response to the feedback jMock gives you
NP> about its design. We recommend using mock objects to test code that
NP> you have full control over: when you have written both the class and
NP> it's outgoing interfaces.
NP> 
NP> When testing code that is using classes that I cannot change I write
NP> an integration test that tests that the code I've written works as I
(Continue reading)


Gmane