using jMock with components

H

Havok

I have recently started improve the unit and component tests to an
existing project and I'm finding it a little difficult to test the
components which in turn, use other components. I have a feeling I've
gone around the world to get a working solution and am wondering if
anyone has any better suggestions / examples.

The examples on the jMock homepage involved creating a mock object and
passing it as a parameter. The problem I have is when one component
uses another, it creates the component internally meaning I have no
chance to mock it.

The solution I have used at the moment is to have all components which
create other components (some of these may be in external libs) do so
via a factory class. Whilst running normally the factory class returns
a real instance, and during the jUnit tests the factory can be
configured to return mocks.

I created a factory interface which exposed the components I needed to
create, an abstract class which implemented static setFactory() and
getFactory() methods and keeps the current factory in a static field,
and two concrete classes one which is the real factory, and one which
returns mocks when configured. The reason I created the two factories
is so I can omit the mock factory (and therefore the dependencies on
jUnit and jMock) when I make a distribution.

When a component X creates component Y using the factory it uses a
syntax like this:
ComponentY cy = Factory.getFactory().getComponentY();

When I am in the setUp of a test for componentX I configure the factory
like so:
Factory testFactory = new TestFactory();
Factory.setFactory(testFactory);
Mock mockComponentY = new Mock(ComponentY.class);
testFactory.mockComponent(ComponentY.class, mockComponentY.proxy());

This seems to work fine in practice, but there are some problems.
Firstly I just have a bad feeling about it that I can't put my finger
on. Secondly it leads to an inconsistant way of instantiating classes
since I obviously don't create everything via the factory, just those
which need to be mocked. Thirdly it's trouble to maintain.since I am
adding getComponentXYZ() methods to two classes and an interface every
time I wish to mock a new component.

I suppose the easy solution for the third point would be to do away
with the interface and merge the abstract and real factory classes
together and create a getComponent(Class c) method which creates a
newInstance of the class using reflection, and have the test factory
override that method. Although I think this limits me to components
with 0-argument constructors.

I'm sure a lot of people have done this before so if there is a common
pattern I should be using I'd really appreciate a pointer to it.

Regards, Paul
 
A

Andrew McDonagh

Havok said:
I have recently started improve the unit and component tests to an
existing project and I'm finding it a little difficult to test the
components which in turn, use other components. I have a feeling I've
gone around the world to get a working solution and am wondering if
anyone has any better suggestions / examples.

:) its a common feeling when starting out...keep with it. Unit testing
our code always means we create code that is different to that we would
create with unittests in mind.... because it has to be testable.
Testable usually means (like you have seen) it needs to have low coupling.

Your original code was highly coupled, create the top component, which
then starts off a chain of sub component creations....
The examples on the jMock homepage involved creating a mock object and
passing it as a parameter. The problem I have is when one component
uses another, it creates the component internally meaning I have no
chance to mock it.

The solution I have used at the moment is to have all components which
create other components (some of these may be in external libs) do so
via a factory class. Whilst running normally the factory class returns
a real instance, and during the jUnit tests the factory can be
configured to return mocks.

This is one of many good approaches - I'll go into some others below -
but don't worry about Abstract factory it is a valid approach.

your implementation may be improved, but the pattern and its usage is sound.
I created a factory interface which exposed the components I needed to
create, an abstract class which implemented static setFactory() and
getFactory() ...

Small point - why the getFactory() method?

Usually its fine to have the createXXXComponent method on the abstract
factory itself, which internally just delegates to the concrete factory.

anyway, on with more useful stuff...
...methods and keeps the current factory in a static field,
and two concrete classes one which is the real factory, and one which
returns mocks when configured. The reason I created the two factories
is so I can omit the mock factory (and therefore the dependencies on
jUnit and jMock) when I make a distribution.

This is good.
When a component X creates component Y using the factory it uses a
syntax like this:
ComponentY cy = Factory.getFactory().getComponentY();

As above, we normally go for:

ComponentY cy = Factory.createComponentY();

This 'hides middle man' from the calling code, relieving the potential
for another coupling within it (i.e. the calling code now knows it has
to get something to then call the create method on - when it doesn't
really need to know - google Law Of Demeter for more).

(oh another small point....its createXxxx() because factories create
stuff. you'd use getComponentXXxx() if you were asking a warehouse )

When I am in the setUp of a test for componentX I configure the factory
like so:
Factory testFactory = new TestFactory();
Factory.setFactory(testFactory);
Mock mockComponentY = new Mock(ComponentY.class);
testFactory.mockComponent(ComponentY.class, mockComponentY.proxy());

This seems to work fine in practice, but there are some problems.
Firstly I just have a bad feeling about it that I can't put my finger
on.

Don't have - its a standard pattern for decoupling - which is needed to
allow testability.

The only possible problem, would be like any pattern abuse - i.e. using
it everywhere, all the time, when in fact a simpler approach would have
the same benefits but be simpler to implement and follow.
Secondly it leads to an inconsistant way of instantiating classes
since I obviously don't create everything via the factory, just those
which need to be mocked.

I wouldn't be concerned with this, within most large Java apps, there's
normally several different means of creating/setting objects at runtime:

AbstractFactories, Factory Methods, Reflection, etc..
Thirdly it's trouble to maintain.since I am
adding getComponentXYZ() methods to two classes and an interface every
time I wish to mock a new component.

I haven't had a chance to use generics with the Abstract factory
pattern, but it should be do-able. this way the factory method would be
something like 'createComponent(T t)'

But in general, its not really a problem to maintain in my experience
(esp seeing as eclipse/intelliJ do it for us) as mocking & faking makes
use of interfaces or class deriving, all the time - its the price of
decoupling.
I suppose the easy solution for the third point would be to do away
with the interface and merge the abstract and real factory classes
together and create a getComponent(Class c) method which creates a
newInstance of the class using reflection, and have the test factory
override that method. Although I think this limits me to components
with 0-argument constructors.

Yes this can be a useful approach - I've used it a few times, but I
prefer the abstract factory or abstract factory method. ymmv
I'm sure a lot of people have done this before so if there is a common
pattern I should be using I'd really appreciate a pointer to it.

Regards, Paul

luckily, yes there's lots of us who have been here, got the t-shirt...etc.

Anyway, some alternatives...

Extract factory method and override -
extract the creation code, into a protected method, then from your
testcase, create a derived (usually an anonymous inner) class which can
stub out the problem methods of the super class. Useful if the super
class is doing things like talking to databases, loading files, etc.

Useful if the super class is your own or not final.


Introduce interface, then extract factory method and override -

Similar to the above, but this time, we add an interface to the real
class, then have the protected factory method return type to be the
interface, rather than the original class.

Useful if the class is your own and so can modify it. Otherwise with
third party or final classes we have to Wrap the class inside a new
class which implements the interface.

Again this is good, your production code now has no direct dependency
upon 3rd party classes, aside from one small wrapper class.


Apply Injection -

nice name for adding a setter or constructor argument to the existing
class, so that your test can create your class under test (CUT), then
change or set the object(s) it collaborates with.


Dependency Inject using reflection.

Much the same as the above, except this time, your CUT uses reflection
to create an instance, so in your tests, you change the string value the
CUT uses so it creates your fake/mock instead.



So there you go, 4 alternatives - out of many other possibles!

If you can, get 'Working Effectively with Legacy Code' by Micheal
Features - its an entire book about doing just what we are talking about.
http://www.amazon.com/gp/product/0131177052/103-7940607-8092646?v=glance&n=283155

In the mean time, here's a link to his original paper that later become
the book. http://www.otug.org/meeting/slides/20051115-MichaelFeathers.pdf


Other than this, as there's only a few others on this list who talk
about TDD & unit testing, you would get alot more help from the yahoo
groups :


http://groups.yahoo.com/group/testdrivendevelopment/

Discussion of the theory and practice of test-driven development (TDD)-
regardless of language.


http://groups.yahoo.com/group/junit/
Discussion of how to use Junit to test, TDDing using Junit, Junit with
Java 1.5...


http://groups.yahoo.com/group/refactoring/
This is a forum for discussions about Refactoring, including tools
associated with Refactoring. It is a place to share and discuss new and
old refactorings in a variety of software languages.


Here's some links which may be useful...

http://www-128.ibm.com/developerworks/java/library/j-mocktest.html
http://www.testdriven.com/modules/news/
http://www.codecomments.com/archive209-2005-3-411269.html
....lots more if needed...

HTH ..if not, ask some questions...

Andrew
 
H

Havok

Hi Andrew,

thanks for taking the time to answer the qestion in detail.

Andrew said:
:) its a common feeling when starting out...keep with it. Unit testing
our code always means we create code that is different to that we would
create with unittests in mind.... because it has to be testable.
Testable usually means (like you have seen) it needs to have low coupling.

Your original code was highly coupled, create the top component, which
then starts off a chain of sub component creations....


This is one of many good approaches - I'll go into some others below -
but don't worry about Abstract factory it is a valid approach.

your implementation may be improved, but the pattern and its usage is sound.


Small point - why the getFactory() method?

In my original version I had a few helpers in the testFactory (setting
up a mock for instance). The production would treat the returned object
as an implementation of the factoryInterface, whilst the test code
would cast the returned object to a testFactory to have access to the
helper methods.
Usually its fine to have the createXXXComponent method on the abstract
factory itself, which internally just delegates to the concrete factory.

anyway, on with more useful stuff...


This is good.


As above, we normally go for:

ComponentY cy = Factory.createComponentY();

This 'hides middle man' from the calling code, relieving the potential
for another coupling within it (i.e. the calling code now knows it has
to get something to then call the create method on - when it doesn't
really need to know - google Law Of Demeter for more).

(oh another small point....its createXxxx() because factories create
stuff. you'd use getComponentXXxx() if you were asking a warehouse )

Oh good point, I've changed this now :)
Don't have - its a standard pattern for decoupling - which is needed to
allow testability.

The only possible problem, would be like any pattern abuse - i.e. using
it everywhere, all the time, when in fact a simpler approach would have
the same benefits but be simpler to implement and follow.


I wouldn't be concerned with this, within most large Java apps, there's
normally several different means of creating/setting objects at runtime:

AbstractFactories, Factory Methods, Reflection, etc..


I haven't had a chance to use generics with the Abstract factory
pattern, but it should be do-able. this way the factory method would be
something like 'createComponent(T t)'

I would like to try it but unfortunately I am only able to use 1.4. In
the end I went with the approach I talked about below (public static
Object createComponent(Class c)) which seems to work well so far,.
Although I'm not sure if it will save me time in the future as I have
had to create a few wrapper classes for external components which don't
have 0 length construtors (Like AXIS's
SOAPConnectionFactory.newInstance().createConnection();).

Can you tell me how the createComponent(T t) method would work? I'm
having trouble seeing how it would be different in principle than
creating the instances using reflection (Although I admit my knowledge
of generics in Java is lacking since I've only read the technical
overview and not written any code).
But in general, its not really a problem to maintain in my experience
(esp seeing as eclipse/intelliJ do it for us) as mocking & faking makes
use of interfaces or class deriving, all the time - its the price of
decoupling.


Yes this can be a useful approach - I've used it a few times, but I
prefer the abstract factory or abstract factory method. ymmv


luckily, yes there's lots of us who have been here, got the t-shirt...etc.

Anyway, some alternatives...

Extract factory method and override -
extract the creation code, into a protected method, then from your
testcase, create a derived (usually an anonymous inner) class which can
stub out the problem methods of the super class. Useful if the super
class is doing things like talking to databases, loading files, etc.

Useful if the super class is your own or not final.


Introduce interface, then extract factory method and override -

Similar to the above, but this time, we add an interface to the real
class, then have the protected factory method return type to be the
interface, rather than the original class.

Useful if the class is your own and so can modify it. Otherwise with
third party or final classes we have to Wrap the class inside a new
class which implements the interface.

Again this is good, your production code now has no direct dependency
upon 3rd party classes, aside from one small wrapper class.


Apply Injection -

nice name for adding a setter or constructor argument to the existing
class, so that your test can create your class under test (CUT), then
change or set the object(s) it collaborates with.

This is the only other method I have used so far, but I found it a
little bit clumsy to pass all of the objects in. After using the
factory for a while I am really starting to like it more.
Dependency Inject using reflection.

Much the same as the above, except this time, your CUT uses reflection
to create an instance, so in your tests, you change the string value the
CUT uses so it creates your fake/mock instead.



So there you go, 4 alternatives - out of many other possibles!

If you can, get 'Working Effectively with Legacy Code' by Micheal
Features - its an entire book about doing just what we are talking about.
http://www.amazon.com/gp/product/0131177052/103-7940607-8092646?v=glance&n=283155

In the mean time, here's a link to his original paper that later become
the book. http://www.otug.org/meeting/slides/20051115-MichaelFeathers.pdf


Other than this, as there's only a few others on this list who talk
about TDD & unit testing, you would get alot more help from the yahoo
groups :


http://groups.yahoo.com/group/testdrivendevelopment/

Discussion of the theory and practice of test-driven development (TDD)-
regardless of language.


http://groups.yahoo.com/group/junit/
Discussion of how to use Junit to test, TDDing using Junit, Junit with
Java 1.5...


http://groups.yahoo.com/group/refactoring/
This is a forum for discussions about Refactoring, including tools
associated with Refactoring. It is a place to share and discuss new and
old refactorings in a variety of software languages.


Here's some links which may be useful...

http://www-128.ibm.com/developerworks/java/library/j-mocktest.html
http://www.testdriven.com/modules/news/
http://www.codecomments.com/archive209-2005-3-411269.html
...lots more if needed...

HTH ..if not, ask some questions...

Andrew

Thanks for the links.

Regards, Paul
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top