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