Spying on real objects?

1,141 views
Skip to first unread message

redsolo

unread,
Jul 9, 2008, 7:16:51 AM7/9/08
to mockito
Hi

Ive switched from jmock to mockito, and are very impressed on how easy
it is to use this library. So, thanks for sharing!

Now I wonder if it is possible to spy on real objects? I had a serious
bug in my code, where I had forgot to close a stream. I tried to build
a test case for it, but noticed that there is no isClosed() method on
streams/readers. I would like to use the real stream object, but make
sure that the close() method is called on it. I wonder if it is
possible to do that with stubbing or mocking? (ie, my production code
uses methods on a real stream object that does their things, but when
the close() method is called, i would like to be able to use
Mockito.verify(stream).close())

I was going to mock the stream itself, but I dont want to stub every
read() call to insert valid data that is used in the production code.

Am I asking for too much, or maybe making it more complex than it is.

regards
//Erik

szczepiq

unread,
Jul 9, 2008, 7:49:10 AM7/9/08
to moc...@googlegroups.com
Hi,

>Now I wonder if it is possible to spy on real objects? I had a serious
>bug in my code, where I had forgot to close a stream. I tried to build
>a test case for it, but noticed that there is no isClosed() method on
>streams/readers.

In your case I would suggest writing a new test that proves that the
stream is closed. I see you already tried that:

>I was going to mock the stream itself, but I don't want to stub every


>read() call to insert valid data that is used in the production code.

Why do you need valid data? Is it a functional test? Can't you write a
new test method where you don't care about data/processing but only
about closing the stream?

About spying on real object (sometimes called "partial mocking"):
We've already had few debates over "partial mocking" features. Have
quick look at mailing list archive.

IMHO, the only clean implementation of spying real objects is:

Foo realFoo = new Foo();
Foo fooSpy = Mockito.spy(realFoo);

//you can optionally stub the spy:
stub(fooSpy.read()).toReturn(1);

//finally you can call methods on a spy - the real implementation is executed
fooSpy.someMethod();

//you can optionally verify the spy:
verify(fooSpy).someMethod();

What do others think about it?

Above feature is not implemented but there is a user who offered to
implement it - I don't know what's the status right now but I can find
out.

Cheers,
Szczepan Faber

Mwanji Ezana

unread,
Jul 9, 2008, 9:04:43 AM7/9/08
to moc...@googlegroups.com
Above feature is not implemented but there is a user who offered to
implement it - I don't know what's the status right now but I can find
out.

Sorry to hijack the thread a little bit. Maybe I missed the message where that implementation was first proposed, because I don't remember having seen it before, but I think it's pretty cool.

I remember that you liked "xUnit Testing Patterns" use of the term "spy", but wouldn't Mockito.partialMock() be more consistent with the current API? Since, from the POV of the test, partial and full mocks aren't doing anything different, maybe the terms should be as close as possible.

Mwanji

Erik Ramfelt

unread,
Jul 9, 2008, 6:23:03 PM7/9/08
to moc...@googlegroups.com
On Wed, Jul 9, 2008 at 1:49 PM, szczepiq <szcz...@gmail.com> wrote:
>
> Hi,
>
>>Now I wonder if it is possible to spy on real objects? I had a serious
>>bug in my code, where I had forgot to close a stream. I tried to build
>>a test case for it, but noticed that there is no isClosed() method on
>>streams/readers.
>
> In your case I would suggest writing a new test that proves that the
> stream is closed. I see you already tried that:
>
>>I was going to mock the stream itself, but I don't want to stub every
>>read() call to insert valid data that is used in the production code.
>
> Why do you need valid data? Is it a functional test? Can't you write a
> new test method where you don't care about data/processing but only
> about closing the stream?

Hmm, you are right. I will take a look at it, and i guess that would
be the easiest way to do it.


> About spying on real object (sometimes called "partial mocking"):
> We've already had few debates over "partial mocking" features. Have
> quick look at mailing list archive.

Will take a look at it.


> IMHO, the only clean implementation of spying real objects is:
>
> Foo realFoo = new Foo();
> Foo fooSpy = Mockito.spy(realFoo);
>
> //you can optionally stub the spy:
> stub(fooSpy.read()).toReturn(1);
>
> //finally you can call methods on a spy - the real implementation is executed
> fooSpy.someMethod();
>
> //you can optionally verify the spy:
> verify(fooSpy).someMethod();
>
> What do others think about it?


I do really like that, and I hope something similar is added to the
mockito api.

Cheers
//Erol

ErikEngerd

unread,
Jul 10, 2008, 4:09:38 AM7/10/08
to mockito
On 10 Jul, 00:23, "Erik Ramfelt" <eramf...@gmail.com> wrote:
> > On Wed, Jul 9, 2008 at 1:16 PM, redsolo <eramf...@gmail.com> wrote:
>
> >> Hi
>
> >> Ive switched from jmock to mockito, and are very impressed on how easy
> >> it is to use this library. So, thanks for sharing!
>
> >> Now I wonder if it is possible to spy on real objects? I had a serious
> >> bug in my code, where I had forgot to close a stream. I tried to build
> >> a test case for it, but noticed that there is no isClosed() method on
> >> streams/readers. I would like to use the real stream object, but make
> >> sure that the close() method is called on it. I wonder if it is
> >> possible to do that with stubbing or mocking? (ie, my production code
> >> uses methods on a real stream object that does their things, but when
> >> the close() method is called, i would like to be able to use
> >> Mockito.verify(stream).close())
>
> >> I was going to mock the stream itself, but I dont want to stub every
> >> read() call to insert valid data that is used in the production code.
>
> >> Am I asking for too much, or maybe making it more complex than it is.
>
> >> regards
> >> //Erik

+1 from me on the spy() feature!

Cheers
Erik

Erik Ramfelt

unread,
Jul 10, 2008, 6:16:14 AM7/10/08
to moc...@googlegroups.com
On Wed, Jul 9, 2008 at 1:49 PM, szczepiq <szcz...@gmail.com> wrote:
>
> Hi,
>
>>Now I wonder if it is possible to spy on real objects? I had a serious
>>bug in my code, where I had forgot to close a stream. I tried to build
>>a test case for it, but noticed that there is no isClosed() method on
>>streams/readers.
>
> In your case I would suggest writing a new test that proves that the
> stream is closed. I see you already tried that:
>
>>I was going to mock the stream itself, but I don't want to stub every
>>read() call to insert valid data that is used in the production code.
>
> Why do you need valid data? Is it a functional test? Can't you write a
> new test method where you don't care about data/processing but only
> about closing the stream?

I actually tested that before sending the email, and I had some
strange results. One of the problem (i guess) is that the method under
test creates a bufferedreader of the mocked Reader. Consider the below
code and test.

public void methodToTest(Reader reader) throws Exception {
BufferedReader bf = new BufferedReader(reader);
String line = bf.readLine();
while (line != null) {
line = bf.readLine();
}
bf.close();
}

@Test
public void assertReaderisClosed() throws Exception {
Reader reader = mock(Reader.class);
methodToTest(reader);
verify(reader).close();
}


* If I did not set up any stubs, the test would never end resulting in
a java out of heap error, it seems that the first bf.readLine() never
returns. I would have expect the test to fail because of a missing
stub.

* Then when I tried to stub out the abstract method
read(char[],int,int) I get a NPE at the stub() line. Or am I doing it
wrong?
Reader reader = mock(Reader.class);
stub(reader.read(isA(char[].class), isA(int.class),
isA(int.class))).toReturn(-1);
methodToTest(reader);


Now Im not sure how to get the test working, as it requires me to know
more and more about the BufferedReader class and how it uses the
methods on the original Reader object (which I really dont care
about). For me it would be so much simpler not to find out what
methods I have to stub in order to spy on the Reader object. Instead
of setting up various stubs for returning -1, it would be nice to just
let the reader do its job and verify that the close method was called.
Thus, adding the spy() method will not require any stubbing on the
reader object, and the test code will be much smaller. It would be
very nice to have small tests as the one below:

public void assertReaderisClosed() throws Exception {
Reader reader = Mockito.spy(new StringReader(""));
test(reader);
verify(reader).close();
}


For the NPE and never ending method call, would you like me to create
issues for them or has them already been fixed? Im currently using
Mockito 1.3.

Regards
//Erik

ErikEngerd

unread,
Jul 10, 2008, 8:26:33 AM7/10/08
to mockito
On 9 Jul, 13:49, szczepiq <szcze...@gmail.com> wrote:
> Hi,
>
> >Now I wonder if it is possible to spy on real objects? I had a serious
> >bug in my code, where I had forgot to close a stream. I tried to build
> >a test case for it, but noticed that there is no isClosed() method on
> >streams/readers.
>
> In your case I would suggest writing a new test that proves that the
> stream is closed. I see you already tried that:
>
> >I was going to mock the stream itself, but I don't want to stub every
> >read() call to insert valid data that is used in the production code.
>
> Why do you need valid data? Is it a functional test? Can't you write a
> new test method where you don't care about data/processing but only
> about closing the stream?
>
> About spying on real object (sometimes called "partial mocking"):
> We've already had few debates over "partial mocking" features. Have
> quick look at mailing list archive.

I think the most important issue is to be able to stub concrete
classes. Using the appropriate verifications then already covers
spying on a few methods.
A useful scenario is where test stubs are used that are sufficient in
most cases as-is, but where specific interactions must be verified for
some test cases.

Currently, mockito allows to stub/spy on concrete classes, but I could
not find any method to stub a concrete class with arguments in the
constructor.
In easymock they solve it through an additional argument
(ConstructorArgs) to the call to create the mock. I think however a
solution could be more elegant in mockito. For instance:

Listener listener = mock(ConcreteListener.class, "hello", 100,
false); // mocking new ConcreteListener("hello", 100, false);

Of course, even more elegant would to to spy on pre-instantiated
objects as suggested above.

Is there currently any method in mockito to mock a concrete class that
has no default constructor?

Cheers
Erik




>
> IMHO, the only clean implementation of spying real objects is:
>
> Foo realFoo = new Foo();
> Foo fooSpy = Mockito.spy(realFoo);
>
> //you can optionally stub the spy:
> stub(fooSpy.read()).toReturn(1);
>
> //finally you can call methods on a spy - the real implementation is executed
> fooSpy.someMethod();
>
> //you can optionally verify the spy:
> verify(fooSpy).someMethod();
>
> What do others think about it?
>
> Above feature is not implemented but there is a user who offered to
> implement it - I don't know what's the status right now but I can find
> out.
>
> Cheers,
> Szczepan Faber
>

szczepiq

unread,
Jul 10, 2008, 9:23:11 AM7/10/08
to moc...@googlegroups.com
> Listener listener = mock(ConcreteListener.class, "hello", 100,
>false); // mocking new ConcreteListener("hello", 100, false);

I'm a bit puzzled what's the benefit of calling real constructor when
I'm creating a mock. Currently, mockito uses Objenesis library to
create mock instances. Objenesis uses various hacks to create
instances which means that created instances are usually in messed up
state. That's fine though, because I'm not calling real methods so I
don't care about the state of an instance.

>Is there currently any method in mockito to mock a concrete class that
>has no default constructor?

mock() method creates mocks regardless of any constructors. It doesn't
use the default constructor because it's risky - what if the
constructor throws an exception? I wouldn't be able to create mocks...

As far as spying is concerned, to make sure real object is in correct
state spy() method requires a ready-to-use instance.

Cheers,
Szczepan Faber

ErikEngerd

unread,
Jul 10, 2008, 11:00:00 AM7/10/08
to mockito


On 10 Jul, 15:23, szczepiq <szcze...@gmail.com> wrote:

> As far as spying is concerned, to make sure real object is in correct
> state spy() method requires a ready-to-use instance.

Spying on objects would be great as that would cover what I want,
namely to have an object in a correct state, yet mock it.
Of course, to make spying complete, it should alos support the
Callback mechanism proposed in another thread and the callback
mechanism should allow methods on the spied on object to be called.

Is there already a feature request for the spy() functionality?

Cheers
Erik

>
> Cheers,
> Szczepan Faber

szczepiq

unread,
Jul 10, 2008, 11:11:20 AM7/10/08
to moc...@googlegroups.com
Before we go with a feature request, let me tell you all about a big
gotcha around proposed spying interface:

List list = new LinkedList();
List spy = spy(list);

//following is impossible:
stub(list.get(0)).toReturn("foo");

When you do stub() mockito performs real method call. E.g. in above
example get(0) method is called on a list. Since the list is empty
IndexOutOfBoundsException is thrown before even mockito realizes that
this is stubbing.

stub() API calls real methods so if the real method has side effects
then I wouldn't be able to use stub() api at all. Which means I would
have to use doReturn() API (not yet implemented :)

doReturn("foo").when(list).get(0);

Cheers,
Szczepan

ErikEngerd

unread,
Jul 10, 2008, 4:30:36 PM7/10/08
to mockito
On Jul 10, 5:11 pm, szczepiq <szcze...@gmail.com> wrote:
> Before we go with a feature request, let me tell you all about a big
> gotcha around proposed spying interface:
>
> List list = new LinkedList();
> List spy = spy(list);
>
> //following is impossible:
> stub(list.get(0)).toReturn("foo");

You probably mean stub(spy.get(0)).toReturn("foo") or not?

>
> When you do stub() mockito performs real method call. E.g. in above
> example get(0) method is called on a list. Since the list is empty
> IndexOutOfBoundsException is thrown before even mockito realizes that
> this is stubbing.

I am wondering now whether mockito should always be used for stubbing.
There are also standard Java constructs to do this that provide the
same and are also descriptive:

List list = new LinkedList() {
Object get(int aIndex) { ..... your stub code here ....}
};
List spy = spy(list);

In the case of stubbing an interface, then mockito is of course really
useful for creating stubs because it avoids having to implement all
methods in the interface. On the other hand, for creating a special
stub based on a concrete class the standard inner class solution is
probably better. The spy is then still useful to verify interactions.
Perhaps the documentation should make a remark that stubbing concrete
classes is best done using inner classes instead of mockito.

>
> stub() API calls real methods so if the real method has side effects
> then I wouldn't be able to use stub() api at all. Which means I would
> have to use doReturn() API (not yet implemented :)

This is why I think stub() should not be used to create stubs based on
concrete classes.

>
> doReturn("foo").when(list).get(0);

If it were up to me, the doReturn API would not be implemented because
it would lead to too many ways to express the same thing. (much like
perl has (1) if (condition) statement; (2) statement if (condition),
(3) unless(condition) statement, and (4) statement unless(condition)).
The result of this would be endless discussion about which style to
use when.

Cheers
Erik

>
> Cheers,
> Szczepan

szczepiq

unread,
Jul 10, 2008, 5:38:56 PM7/10/08
to moc...@googlegroups.com
> You probably mean stub(spy.get(0)).toReturn("foo") or not?

Yes, sorry, my mistake.

>I am wondering now whether mockito should always be used for stubbing.
>There are also standard Java constructs to do this that provide the
>same and are also descriptive:

Thank you for that. I totally agree that sometimes hand written
mocks/stubs are just better option.

>If it were up to me, the doReturn API would not be implemented

Me too, but this @#@# java language... Void is not a decent type so I
cannot use stub() API for void methods. So there has to be an extra
API for void methods, hence stubVoid() that will be replaced by
doReturn(). Fortunately, stubbing voids is a rare case and stubbing
real objects even rarer.

Cheers,
Szczepan Faber

Erik Ramfelt

unread,
Jul 14, 2008, 5:18:05 PM7/14/08
to moc...@googlegroups.com
On Thu, Jul 10, 2008 at 5:11 PM, szczepiq <szcz...@gmail.com> wrote:
>
> Before we go with a feature request, let me tell you all about a big
> gotcha around proposed spying interface:
>
> List list = new LinkedList();
> List spy = spy(list);
>
> //following is impossible:
> stub(list.get(0)).toReturn("foo");
>
> When you do stub() mockito performs real method call. E.g. in above
> example get(0) method is called on a list. Since the list is empty
> IndexOutOfBoundsException is thrown before even mockito realizes that
> this is stubbing.

It is sure a big gotcha.I havent looked at the source code so this may
be a naive idea, so please bare with me. But couldnt the spy() method
create a mock object with a reference to the real object. Stubbing
works like with common mocks. When a method is called on the mock, it
will check if there are any stubs registered for the mock and use it.
If there are no stubs, it will call the real method on the real
object.


> stub() API calls real methods so if the real method has side effects
> then I wouldn't be able to use stub() api at all. Which means I would
> have to use doReturn() API (not yet implemented :)

I think naming the method to Mockito.spy() would imply that you are
spying on an object and not mocking it, ie spying should not affect
the object. If its named Mockito.partialMock(), it is not clear that
stubbing is not "allowed".

regards
//Erik

szczepiq

unread,
Jul 15, 2008, 7:42:02 AM7/15/08
to moc...@googlegroups.com
>It is sure a big gotcha.I havent looked at the source code so this may
>be a naive idea, so please bare with me. But couldnt the spy() method
>create a mock object with a reference to the real object. Stubbing
>works like with common mocks. When a method is called on the mock, it
>will check if there are any stubs registered for the mock and use it.
>If there are no stubs, it will call the real method on the real
>object.

stub( spy.foo()
).toReturn()
^
This is exactly how it works but a this point ^ mockito doesn't know
that you're stubbing (welcome to the java :). So, mockito calls real
method foo(). Now if this is an ordinary mock than it's fine because
foo() is harmless. However if the spy is a real object, then real
foo() is called and all side effects of foo() might bite.

>I think naming the method to Mockito.spy() would imply that you are
>spying on an object and not mocking it, ie spying should not affect
>the object. If its named Mockito.partialMock(), it is not clear that
>stubbing is not "allowed".

... <-- This is where you make your proposal... :-)

Cheers,
Szczepan Faber

Erik Ramfelt

unread,
Jul 16, 2008, 7:43:38 AM7/16/08
to moc...@googlegroups.com
On Tue, Jul 15, 2008 at 1:42 PM, szczepiq <szcz...@gmail.com> wrote:
>
>>It is sure a big gotcha.I havent looked at the source code so this may
>>be a naive idea, so please bare with me. But couldnt the spy() method
>>create a mock object with a reference to the real object. Stubbing
>>works like with common mocks. When a method is called on the mock, it
>>will check if there are any stubs registered for the mock and use it.
>>If there are no stubs, it will call the real method on the real
>>object.
>
> stub( spy.foo()
> ).toReturn()
> ^
> This is exactly how it works but a this point ^ mockito doesn't know
> that you're stubbing (welcome to the java :). So, mockito calls real
> method foo(). Now if this is an ordinary mock than it's fine because
> foo() is harmless. However if the spy is a real object, then real
> foo() is called and all side effects of foo() might bite.

duh, ok :).. I guess the only way to solve it is to add a state on the
object being spied on that says "now the preparations have ended, call
the real methods from now". And I dont think that is along the
simplicity that Mockito delivers.

Perhaps if someone must stub a method in an object, he could create a
normal mock of the class, stub the methods on the mock; and the supply
it in the Mockito.spy() method. That way, stubbing works exactly as
before. (Of course, not setting a mock in Mockito.spy(Reader.class)
works)


// Create a mock and stub some methods on it
Reader mock = mock(Reader.class);
stub(mock.ready()).toThrow(new RuntimeException());

// Create a real object and add the stubs from the mock to it
Reader reader = Mockito.spy(new StringReader("some text"), mock);

// Call the "real" methods on the "real" reader object
reader.read();

// Calling ready() on "real" object matches the stub and throws a
runtimeexception
reader.ready();


>>I think naming the method to Mockito.spy() would imply that you are
>>spying on an object and not mocking it, ie spying should not affect
>>the object. If its named Mockito.partialMock(), it is not clear that
>>stubbing is not "allowed".
>
> ... <-- This is where you make your proposal... :-)

Go with Mockito.spy().

//Erik

Reply all
Reply to author
Forward
0 new messages