You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cocoon.apache.org by Ugo Cei <ug...@apache.org> on 2004/07/23 19:05:26 UTC

Mock objects

In the Cocoon tests one can find a handful of "Mock Objects", for 
instance in the o.a.c.environment.mocks package. These mocks are used 
to stub out objects that are hard and/or expensive to create or 
manipulate, like a Request or Environment. You can carry out a certain 
number of tests with this kind of mocks, but there are limits. One 
limit is that you cannot easily set up and test expectations regarding 
the interaction between the method under test and its "fixture" which 
can be made up of such mocks. Imagine, for example, that you want to 
test the connectPipeline method of AbstractProcessingPipeline:

     /**
      * Connect the next component
      */
     protected void connect(Environment environment,
                            XMLProducer producer,
                            XMLConsumer consumer)
     throws ProcessingException {
         XMLProducer next = producer;
         // Connect next component.
         next.setConsumer(consumer);
     }

     /**
      * Connect the XML pipeline.
      */
     protected void connectPipeline(Environment environment)
     throws ProcessingException {
         XMLProducer prev = this.generator;

         Iterator itt = this.transformers.iterator();
         while (itt.hasNext()) {
             Transformer next = (Transformer) itt.next();
             connect(environment, prev, next);
             prev = next;
         }

         // insert the serializer
         connect(environment, prev, this.lastConsumer);
     }

A possible test is verifying that the setConsumer method on the 
generator is called with the correct argument, like a transformer. How 
can you do that if the XMLProducer class does not provide a getConsumer 
method? We could add it, but it would force all implementors to provide 
an implementation and it would not be possible if the interface in 
question were from an external library.

What is needed is an implementation of XMLConsumer that provides a way 
to set an expectation that the setConsumer method will be called and 
verify if this is indeed the case. Simple stubs do not provide this 
capability. This is why some people started drawing a line between 
simple "stubs" and "real mocks". You can read more about this here [1].

Now, implementing mock objects for the interfaces we want to mock is 
not that hard but is tedious and is better left to tools. There are a 
couple of Java libraries out there that are meant to be used with JUnit 
and that we could add to our arsenal:

- jMock		http://www.jmock.org/index.html
- EasyMock	http://www.easymock.org/index.html

What I am asking here is whether someone has experience with the above 
mentioned frameworks and feels like suggesting one over the other, or 
maybe a third alternative.

	Thanks in Advance,

		Ugo

[1] http://www.martinfowler.com/articles/mocksArentStubs.html

-- 
Ugo Cei - http://beblogging.com/

Re: Mock objects

Posted by Brian McCallister <mc...@forthillcompany.com>.
basic form -- with extensive unit test coverage, and mock usage, you 
really do have two clients for every piece of code -- the system and 
the test harness.

If you don't maintain loose coupling and low dependencies you find out 
really quickly, and get a system where making small changes breaks a 
lot of seemingly unrelated tests, which is incredibly annoying.

-Brian

On Jul 24, 2004, at 4:25 PM, Ugo Cei wrote:

> Il giorno 24/lug/04, alle 22:21, Brian McCallister ha scritto:
>
>> When you put a mock in an object, which is used by what you are 
>> testing (easy to do) in order to make behavior correctly you get 
>> non-obvious dependencies for internal changes. Really the rule should 
>> be "ruthlessly obey the Law of Demeter."
>>
>> Does this make any sense?
>
> In theory, yes, I can follow you. But I have too little experience 
> with mocks (and unit testing in general) to be able to appreciate the 
> finer points. Anyway, thanks.
>
> -- 
> Ugo Cei - http://beblogging.com/



Re: Mock objects

Posted by Ugo Cei <ug...@apache.org>.
Il giorno 24/lug/04, alle 22:21, Brian McCallister ha scritto:

> When you put a mock in an object, which is used by what you are 
> testing (easy to do) in order to make behavior correctly you get 
> non-obvious dependencies for internal changes. Really the rule should 
> be "ruthlessly obey the Law of Demeter."
>
> Does this make any sense?

In theory, yes, I can follow you. But I have too little experience with 
mocks (and unit testing in general) to be able to appreciate the finer 
points. Anyway, thanks.

-- 
Ugo Cei - http://beblogging.com/

Re: Mock objects

Posted by Brian McCallister <mc...@forthillcompany.com>.
It is a good thing, but can be frustrating as we all like shortcuts.

The cost is when you have a hug suite of unit tests (good thing!) but 
they are on moderately coupled code (eh thing), and you want to 
refactor some smelly thing (good thing!).

You do, you *know* it behaves the same way.

50% of unit tests now fail with a message like:

"unexpected call 'getFoo()' on 'foo'"

And you rollback your change because fixing the tests is a bigger task 
than you are willing to stomach for the small improvement.

The problem here was that it is easy to make unit tests very fragile 
when working with even moderately coupled code -- and doing whitebox 
testing. If you are passing  a mock into a class in constructor, and 
you know what the calls against it will be, you tend to 
mock.expectAndReturn(..) on them.

This is fine, and is correct.

When you put a mock in an object, which is used by what you are testing 
(easy to do) in order to make behavior correctly you get non-obvious 
dependencies for internal changes. Really the rule should be 
"ruthlessly obey the Law of Demeter."

Does this make any sense?

-Brian

On Jul 24, 2004, at 3:48 PM, Ugo Cei wrote:

> Il giorno 24/lug/04, alle 21:00, Brian McCallister ha scritto:
>
>> I love mocks, but they do force you to decouple.
>
> Isn't this supposed to be a good thing, or there are hidden costs?
>
> -- 
> Ugo Cei - http://beblogging.com/



Re: Mock objects

Posted by Ugo Cei <ug...@apache.org>.
Il giorno 24/lug/04, alle 21:00, Brian McCallister ha scritto:

> I love mocks, but they do force you to decouple.

Isn't this supposed to be a good thing, or there are hidden costs?

-- 
Ugo Cei - http://beblogging.com/

Re: Mock objects

Posted by Brian McCallister <mc...@forthillcompany.com>.
I've used com.mockobjects... ( 
http://www.mockobjects.com/FrontPage.html ) the most and had good 
experience. Played with jMock some, and like some of their ideas a lot, 
but not enough to have a strong opinion. It is quite different.

A couple things I have found using the dynamic proxy based mock object 
libraries:

Don't use a lot of mocks unless you are comfortably decoupling your 
code to a very high degree.

Don't have mocks return mocks. This is an example of the coupling thing 
above.

Don't have non-mock's return mocks. See coupling.

Make sure to write very loosely coupled code.

When writing unit tests using mocks, make sure they are really unit 
tests, not integration tests. I cannot stress this one enough.

=)

I love mocks, but they do force you to decouple.

-Brian

On Jul 23, 2004, at 1:05 PM, Ugo Cei wrote:

> In the Cocoon tests one can find a handful of "Mock Objects", for 
> instance in the o.a.c.environment.mocks package. These mocks are used 
> to stub out objects that are hard and/or expensive to create or 
> manipulate, like a Request or Environment. You can carry out a certain 
> number of tests with this kind of mocks, but there are limits. One 
> limit is that you cannot easily set up and test expectations regarding 
> the interaction between the method under test and its "fixture" which 
> can be made up of such mocks. Imagine, for example, that you want to 
> test the connectPipeline method of AbstractProcessingPipeline:
>
>     /**
>      * Connect the next component
>      */
>     protected void connect(Environment environment,
>                            XMLProducer producer,
>                            XMLConsumer consumer)
>     throws ProcessingException {
>         XMLProducer next = producer;
>         // Connect next component.
>         next.setConsumer(consumer);
>     }
>
>     /**
>      * Connect the XML pipeline.
>      */
>     protected void connectPipeline(Environment environment)
>     throws ProcessingException {
>         XMLProducer prev = this.generator;
>
>         Iterator itt = this.transformers.iterator();
>         while (itt.hasNext()) {
>             Transformer next = (Transformer) itt.next();
>             connect(environment, prev, next);
>             prev = next;
>         }
>
>         // insert the serializer
>         connect(environment, prev, this.lastConsumer);
>     }
>
> A possible test is verifying that the setConsumer method on the 
> generator is called with the correct argument, like a transformer. How 
> can you do that if the XMLProducer class does not provide a 
> getConsumer method? We could add it, but it would force all 
> implementors to provide an implementation and it would not be possible 
> if the interface in question were from an external library.
>
> What is needed is an implementation of XMLConsumer that provides a way 
> to set an expectation that the setConsumer method will be called and 
> verify if this is indeed the case. Simple stubs do not provide this 
> capability. This is why some people started drawing a line between 
> simple "stubs" and "real mocks". You can read more about this here 
> [1].
>
> Now, implementing mock objects for the interfaces we want to mock is 
> not that hard but is tedious and is better left to tools. There are a 
> couple of Java libraries out there that are meant to be used with 
> JUnit and that we could add to our arsenal:
>
> - jMock		http://www.jmock.org/index.html
> - EasyMock	http://www.easymock.org/index.html
>
> What I am asking here is whether someone has experience with the above 
> mentioned frameworks and feels like suggesting one over the other, or 
> maybe a third alternative.
>
> 	Thanks in Advance,
>
> 		Ugo
>
> [1] http://www.martinfowler.com/articles/mocksArentStubs.html
>
> -- 
> Ugo Cei - http://beblogging.com/



Re: Mock objects

Posted by bernhard huber <be...@gmx.at>.
hi,
<snip/> 
> What I am asking here is whether someone has experience with the above 
> mentioned frameworks and feels like suggesting one over the other, or 
> maybe a third alternative.
> 
i don't have experience using any of the two frameworks, but
there is an comparision http://www.jmock.org/easymock-comparison.html,
helping to make choice.

For me it was most interesting reading: "jMock is a design tool not a
testing tool."

regards bernhard

-- 
+++ GMX DSL-Tarife 3 Monate gratis* +++ Nur bis 25.7.2004 +++
Bis 24.000 MB oder 300 Freistunden inkl. http://www.gmx.net/de/go/dsl