Eedanna / mockito

Automatically exported from code.google.com/p/mockito
0 stars 0 forks source link

allow creating a mock of multiple interfaces #51

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
allow creating a mock of multiple interfaces

Original issue reported on code.google.com by szcze...@gmail.com on 28 Jan 2009 at 1:52

GoogleCodeExporter commented 8 years ago
I would like to add that it should not just be multiple interfaces, but a class 
and 
one or more interfaces.

Original comment by karlgsch...@gmail.com on 28 Jan 2009 at 2:08

GoogleCodeExporter commented 8 years ago
Issue 59 has been merged into this issue.

Original comment by szcze...@gmail.com on 18 Feb 2009 at 10:02

GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
See discussion thread, which describes the problem.
http://groups.google.com/group/mockito/browse_thread/thread/60ce44174c7dd3fe/87d
ab35b19c1ee16

Original comment by iczechowski@gmail.com on 15 Apr 2009 at 1:21

GoogleCodeExporter commented 8 years ago
If someone follows this issue then we need to know how really it is useful? We'd
prefer to keep Mockito API slim (please, not another overloaded mock() method!).

We're waiting for code samples with legitimate case for this feature.

Original comment by szcze...@gmail.com on 21 Apr 2009 at 10:23

GoogleCodeExporter commented 8 years ago
I think this is useful. We had a usecase (also Webservices - JAXB in our case - 
if I
remember correctly) and could not write a test with mockito for it.
Is it really required to overload the mock() method? A vararg should do the 
trick to
keep the api as is and also support multiple interfaces I think.

Original comment by knista.peter on 22 Apr 2009 at 6:21

GoogleCodeExporter commented 8 years ago
The problem among other things is related to generics.  Consider the following 
methods:

public <T extends Point & Colored> T getColoredPoint();

or

public <T extends Component & Highlightable> void doHighlight(T instance);

Some might argue that you shouldn't create methods like that, but I will 
heartily 
disagree.  Such method signatures add clarity and safety.  Since the generics 
parameters can be bound by one class or interface and any number of additional 
interfaces, it is necessary that Mockito be able to provide the ability to mock 
the 
same constraints.

Currently, to mock any output or input for those methods, I am required to 
create 
some class that extends/implements all of the pieces of the puzzle and mock it. 
 My 
code is now littered with Mock objects.  It is no longer clean and 
straightforward.  
The reason I moved to Mockito was to rid myself of these types of objects.

Original comment by karlgsch...@gmail.com on 22 Apr 2009 at 12:20

GoogleCodeExporter commented 8 years ago
>Currently, to mock any output or input for those methods, I am required to 
create 
>some class that extends/implements all of the pieces of the puzzle and mock it.

I don't play against those methods but they seem not to be good candidates to 
mock
their output/input. Wouldn't you prefer to use real objects for those? 

It seems that the case for multi-interface mocks is to mock method parameters /
method returnables. Those objects are (following Misko Hevery's nomenclature 
because
I like it ;) *newables* and it's best to use real implementations of those. I'm 
just
hoping Mockito is not becoming a library for making it easy to create instances 
of
objects that are difficult to create. Because for this problem there are 
completely
different resolutions & patterns. Tell us your thoughts - does it makes sense 
what
I'm saying?

Original comment by szcze...@gmail.com on 22 Apr 2009 at 8:14

GoogleCodeExporter commented 8 years ago
I guess I don't understand how using the "newable" makes it easy to validate 
calls 
on the object.  The point, for me, of using the mock is not in creating 
"difficult" 
objects, but in ensuring that specific things occur to the mocked object.

Original comment by karlgsch...@gmail.com on 23 Apr 2009 at 12:53

GoogleCodeExporter commented 8 years ago
Ok, could you post an example with some code that you had to manually implement 
an
adapter where you preferred to use Mockito?

Original comment by szcze...@gmail.com on 23 Apr 2009 at 9:38

GoogleCodeExporter commented 8 years ago
Actually, I can't, which is unfortunate.  The code is question is considered 
proprietary and I can't release it or the tests.  I can take a stab at 
describing 
the problem more fully.  So here goes:

I have a set of objects that I need to design that have commonalities, but the 
commonalities are a mix-and-match.  To tackle this problem, I created a series 
of "aspect" interfaces.  So, class A implements I and J, while B implements J 
and K, 
and C implements I, K and L, etc.  As you can see there is no clear hierarchy 
between these objects.  True AOD might be the right answer, but that's not 
going to 
happen (politics).  So the best I can do is these "aspect"-styled interfaces.  
What 
I need to test is that the various combinations are handled correctly.  I could 
pass 
in mocks of the classes, but I don't know them at that point in the 
development, so 
I am currently forces to mock an abstract class that implements the 
combinations.

I hope that's a bit more clear.  Thanks for your patience.

Original comment by karlgsch...@gmail.com on 23 Apr 2009 at 12:37

GoogleCodeExporter commented 8 years ago
When I have had to mock a class which implements multiple interfaces I would 
declare
something like this among the class fields, or just above the test method:

interface Tiger extends Running, Biting {}

I could then mock it as if it were a class implementing both. The same could be 
done
for a class implementing many interfaces, as well as to mock a concrete class
implementing many interfaces e.g.:

abstract class Tiger extends Cat implements Running, Biting {}

I believe this gives all the freedom you want without any overhead, if anything 
it
would be more readable than a varargs mock call. And if you added interfaces to 
the
class you want to mock, you'd have to visit the test to change it anyway, so 
there no
advantage there.

The only downside I can see would be if the base class didn't have a default
constructor then you would have to provide one to match, but it should only add 
a
little noise... but it's still a disadvantage.

Don't see any great advantage in adding the capability to Mockito... unless 
there's
use cases I haven't come across, or disadvantages I don't see...?

Regards,
Graham

Original comment by Grundlefleck@gmail.com on 23 Apr 2009 at 7:58

GoogleCodeExporter commented 8 years ago
I consider your Tiger examples ugly and noisy, but I respect your preference.  
I do 
something similar now; I just don't like it. ;)

As I see it, mock(A, B, C, ...) is very clear on what I am creating and 
testing.  It 
happens at the time I request the mock and when I view declarations it's 
exactly 
where I need it to be.  Having to find a Tiger hidden in the woods to determine 
exactly what it looks like adds more indirection to the test than I like.

I also believe that the assumption you have of adding an interface means 
changing 
tests is also incorrect.  The current method imlpementations shouldn't change 
(without my knowledge and permission) when I add an interface and if I need to 
change the tests to cope with the additional interface they are probably 
testing at 
the wrong level.

Karl

Original comment by karlgsch...@gmail.com on 23 Apr 2009 at 8:11

GoogleCodeExporter commented 8 years ago
One more thing: I think this is going to come down to where the user believes 
the 
noise is.  Graham, for instance (and I hope I'm not misquoting), believes it 
would 
be noisy to have a mock(...).  I believe the noise is involved in creating 
dummy 
classes to mock(Dummy).

I appreciate the time and consideration of this point.  There is nothing more 
that I 
enjoy than a good archetectural debate.

Thanks,

Karl

Original comment by karlgsch...@gmail.com on 23 Apr 2009 at 8:14

GoogleCodeExporter commented 8 years ago
I think I went a bit too far when I said it is more readable... your point about
having to look for the declaration is a good one. And the second point about 
'having'
to change it was maybe mis-communicated, what I meant was if (for whatever 
reason)
you had to change a declaration to account for a new interface the same would 
apply
to both, so neither way has anything over the other. I admit I was just 
spilling out
ideas of how the two approaches compare ;-)

I still see one advantage, however this may also be to do with personal 
preference,
consider if I had the call:

MyThing mockMyThing = mock(FirstInterface.class, SecondInterface.class,
ThirdInterfaceWithALongName.class); 

If this was happening in a few places I'd probably extract the mocking to a 
method of
it's own, if only to save me on typing at least(!), so there's a layer of 
indirection
there anyway, and following that is comparable to following the declaration of
Tiger.class in my opinion. If it's done once in a setUp method, I would probably
leave as is, but once again, it's an indirection from a particular test method.

Most of my points were that except under a few conditions* the two approaches 
are
pretty much comparable, the difference being that manually crafting your 
multiple
interfaces is already there in the Java language, so there's zero effort to do 
it
that way.

Regards,
Graham

* with non-default constructors, or when there's not much typing involved, the
mock(...) method is a clear winner

Original comment by Grundlefleck@gmail.com on 23 Apr 2009 at 9:03

GoogleCodeExporter commented 8 years ago
Oh, and when I talked about 'zero effort', I of course meant that in terms of 
Mockito
contributor effort! :)

Regards,
Graham

Original comment by Grundlefleck@gmail.com on 23 Apr 2009 at 9:09

GoogleCodeExporter commented 8 years ago
Hello, I see the discussion has warmed up!

Firstly, I don't vote against aspect-style interfaces. What I wanted to see is 
some
code that requires to mock multiple interfaces because I have a feeling that we
shouldn't mock them at all :)

Let me try to explain it so you can feedback. I'm going to use some of Misko 
Hevery's
nomenclature because I think it's cool. I'm not an ardent reader of his 
writings -
I'm just stealing the names and using it quite badly (sorry Misko).

Let's divide objects into 2 categories: injectables (services, DAOs, etc) & 
newables
(entities, supporting objects, Strings, spam).

class SomeClass {

  EmailService emailService; //injectable
  UserRepository userRepository; //injectable

         //newable     //newable  
  public User findUser(String name) {...
                         //newable   //newable
  public void deleteUser(User user, Reason reason) {...

In most cases, in order to achieve highly maintainable, readable, natural code I
would never mock newables. Only injectables will be mocked if necessary. The 
test
should be able to create & use newables with ease - if it cannot then the design
should be changed so that newables are easy to create & use (hint: you'll get 
it for
free with TDD :).

Above might sound a bit dogmatic but... well... so be it :) Also, I cannot give 
you
any proof that above bold guidelines actually make the code better - that would
require sitting together on some codebase and and some experimenting. (Well, I 
could
try to explain it but it could be a lengthy post).

Let's get to the point. From my experience with classes that implement multiple
interfaces it was never required for the injectable to be mocked with multiple
interfaces. Simply because injectable is a statement of dependency - the class
describes that it needs exactly this type in order to work correctly. So I 
don't need
to use multi-interface mocking for injectables. I might need it for newables, 
though,
but those guys should not really be mocked.

I'm hungry and sleepy now and hopefully what I wrote make sense :)

Original comment by szcze...@gmail.com on 25 Apr 2009 at 8:09

GoogleCodeExporter commented 8 years ago
Well, that's seem very well thought out, but the problem is, I am injecting 
these 
classes.  My base class is a RenderingPipeline, which is a queue for adding 3D 
visualization tasks to the display.  My aspect interfaces come into play, when 
I 
have a delegate class for interacting and controling a single aspect: 
RenderingPipeline & A.  I may have 4 or 5 classes that extend RenderingPipeline 
and 
implemenet A.  If you consider this newable, then the "right way" to test it is 
state-based.  So, I need to check the state of RenderingPipeline & A, but 
that's not 
really possible, since it's mainly a rendering engine that produces output.  I 
could 
test that the output of RenderingPipeline & A is expected but now my test 
covers two 
layers and is dependent on a specific RenderingPipeline & A implementation.  I 
already have tests to ensure that each RenderingPipeline instance produces 
valid 
output from valid input.  What I want to test is that my controller class which 
delegates to this pipeline is performing the correct calls with the correct 
parameters.  I need to verify behavior, not state, since differing pipeline 
produce 
different results from the same input.

Original comment by karlgsch...@gmail.com on 27 Apr 2009 at 3:17

GoogleCodeExporter commented 8 years ago
ok, let's do it.

What about a fluent interface like:

mock(Foo.class).alsoImplement(Bar.class, Baz.class)?

Anyone can contribute a patch?

Original comment by szcze...@gmail.com on 30 Apr 2009 at 3:22

GoogleCodeExporter commented 8 years ago
The fluent interface idea is interesting, but mock returns an instance of Foo, 
which 
doesn't (by default) contain an alsoImplement method.  For fluency, I'd 
recommend 
adding a implementing(Class<?>...interfaces) method and changing mock (or 
rather 
overloading mock) with:
mock(Foo.class, implementing(Bar.class, Baz.class), "name");

That would add two more mock variants, one for named and unamed mocks.  
Possibly 
need an additional one for ReturnValues?

implementing() would just return a simple wrapper class used by the other 
classes to 
add the additional interfaces.

I took a quick look at the source today and I might be able to contribute 
something.

Karl

Original comment by karlgsch...@gmail.com on 5 May 2009 at 4:43

GoogleCodeExporter commented 8 years ago
Here's a patch using my implementing() idea.  I added some tests to 
ClassImposterizerTest and added a TODO in ClassImposterizer.  Not sure how you 
folks 
would want to handle bad input at that point.  I didn't add any more test as it 
looks like you don't test the statics when the code they rely on is tested.

Anyway, this patch should get you started.

Karl

Original comment by karlgsch...@gmail.com on 5 May 2009 at 6:02

Attachments:

GoogleCodeExporter commented 8 years ago
Cool, I'll look at it. Thanks!

Original comment by szcze...@gmail.com on 5 May 2009 at 7:34

GoogleCodeExporter commented 8 years ago
Ok, it's checked in to trunk but I'm still working on tuning it up

Original comment by szcze...@gmail.com on 10 May 2009 at 8:42

GoogleCodeExporter commented 8 years ago
Ok, done in trunk. The api is as follows:

mock(Foo.class, withSettings().extraInterfaces(Bar.class));

Post here if you have better ideas on the API.

Original comment by szcze...@gmail.com on 12 May 2009 at 9:07

GoogleCodeExporter commented 8 years ago

Original comment by szcze...@gmail.com on 9 Jun 2009 at 3:15