>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
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.
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
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
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
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
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
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
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
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