> Am I missing something or such chaining is impossible with Mockito
> stubs?
You're right - chaining return values is impossible in Mockito.
We talked about this feature here:
http://groups.google.com/group/mockito/browse_thread/thread/e73e29d649a3b80a
Do you often use this feature? I never used it and I couldn't find a
good scenario to justify it. On the contrary: it doesn't promote
simple and focused test methods (look at the example from EasyMock -
it's a bit scary...). Do you want it in Mockito?
Cheers,
Szczepan Faber
Anyway, I will look deeper at your example soon. Maybe stubs with
ability to 'stack' different answers is the way to go...
Thanks,
Szczepan Faber
>Today it turned out that there are too
>so many scenarios that I want to test
>that I would be forced to write a separate
>stub for each of them
'Forced' is such a bad word. I would say 'guided to do the right thing' :)
I can see that andReturn(1).andReturn(2).andReturn(null) can be useful
in cases where I deal with mocking *iterator-like objects*. But I
would argue that this happens very often and if it does then there are
better ways of testing it. The example you provided is indeed a case
of mocking an *iterator-like object* (Meter.readValues()).
However for other cases (e.g. non-iterators), I think that being
forced to write separate stub is a good thing. Can you show some code
that proves me wrong?
I looked again at your example with Meter.readValues() method:
>I want to stub readValues() method so it returns a 10 different
So your test ends up like that (I will use hypothetical syntax):
stub(meter.readValues())
.toReturn(mapOne)
.thenReturn(mapTwo)
.thenReturn(mapThree)
.thenReturn(mapFour)
.thenReturn(mapFive)
.thenReturn(mapSix)
.thenReturn(mapSeven)
.thenReturn(mapEight)
.thenReturn(mapNine)
.thenReturn(mapTen)
.thenReturn(emptyMap);
Isn't it a bit overkill to chain 10 return values on a mock to prove
correctness of some conditional logic (e.g. creation of events based
on values from meter)?
But ok, let's stick to your example with mocking 10-element iterator.
Mockito doesn't support mocking iterators. I'm forced to think more
about code under test...
Whoever uses Meter is probably doing something like that:
Map map = meter.readValues();
while (!map.isEmpty()) {
//***** all that conditional logic that require 10
different maps to assert that it works ****
map = meter.readValues();
}
What if Meter extended Iterable interface?
interface Meter extends Iterable<Map> {
void connect();
void close();
}
Then, whoever uses meter would do this:
foreach(Map values : meter) {
//***** all that conditional logic that require 10
different maps to assert that it works ****
}
Suddenly stubbing (even using Mockito!) becomes easy:
List maps = asList(mapOne, mapTwo, mapThree, mapFour, mapFive, mapSix,
mapSeven, mapEight, mapNine, mapTen, emptyMap);
stub(meter.iterator()).toReturn(maps.iterator());
What do you say - is it better now?
Finally, here is my dilemma: shall I implement
thenReturn().thenReturn() so that:
+ i can mock iterators
- there will be tests with 10X thenReturn() in my codebase, that can
be implemented better and tested nicer.
or not, and then:
+ i don't mock iterators: tests are simple and the code is forced to
be simple (hopefully)
- not having thenReturn() may be considered as a weakness so people
will still use current mocking libraries. There will be tests with 10X
andReturn() anyway because other mocking libraries can do that.
Or maybe I'm just still waiting for a good example... :D
Cheers,
Still-thinking-about-it Szczepan Faber
That's a fair point :) Can you show us the code that uses Meter object?
Cheers,
Szczepan Faber
(sorry, Off-Topic. I couldn't help myself :)
S
On 17 Apr 2008, at 13:25, Jagger wrote:
> Simply speaking I want some values returned in a row then
> two exceptions and then some values again. Now I must
> write a stub by myself to test such scenarios.
Steve Freeman
http://www.mockobjects.com
Winner of the Agile Alliance Gordon Pask award 2006
Simply, because I want to test such a scenario
- five value maps are returned in a row;
- then there are some communication problems or somebody
has disconnected the meter but connected it immediately back again
(for example it causes MeterException to be thrown twice);
- after quick recovery five values are returned again in a row.
No thanks, tried that. Didn't work, as I already told you :D
Let's get back to the Meter.
>- five value maps are returned in a row;
>- then there are some communication problems or somebody
>has disconnected the meter but connected it immediately back again
>(for example it causes MeterException to be thrown twice);
>- after quick recovery five values are returned again in a row.
As Mwanji says, it looks more like an integration test to me.
I wouldn't test the 'for' loop using 5 examples. The maximum should be
2. We all agree that the 'for' loop is pretty much stable feature of
java, right? :)
The problem at hand is the retry mechanism that makes the whole thing
difficult to test. How would I make it simpler? For example, I could
hide away the trickiness of try-ooups-retry in some kind of
RetryingMeter that decorates the Meter (or multiple meters). After
all, it's the contract of the Meter that says: "if I fail, try again
up to X number of times". Maybe it's nicer to keep that retry logic
away from clients of the Meter class.
The only problem now is how to test RetryingMeter (I don't have to
show the code here, do I? It's just a decorator that retries...). In
order to do that using the best mocking library is... roll your own
mock. It seems mockito needs this:
stub(meter.readValues())
.toReturn(foo)
.toThrow(new RuntimeException())
.toReturn(bar);
Me and Felix tried to investigate what's better in the case of retry
mechanism: rolling own mock or stretching the mock library. We will
document our findings soon. I'm getting convinced that this feature is
a cool thing. I'm just a bit scared how easily can it be abused to
write code that smells funny.
Cheers,
Szczepan Faber
PS.
Jagger, go try jmock and tell us what you think! Just be lenient for Steve...
Another option to consider is wrapping the Map in a more meaningful
object which you would be able to query about its situation. I'm
developing an increasing aversion to unwrapped collections.
S.
Steve Freeman
It is already in trunk. Snapshot builds can be downloaded here:
http://hudson.ramfelt.se/job/Mockito
I'm hoping to release 1.4 pretty soon.
My advice about mocking ResultSet: don't :). Few days ago my friend
showed me a really nice implementation of hand made stub for
ResultSet. It was based of 'fluent builder' pattern and it really
looked very nice in test methods.
Cheers,
Szczepan Faber
On Tue, Jun 17, 2008 at 3:05 PM, Marc-Andre Houle <mho...@gmail.com> wrote:
>
> Is the implementation going well? Will it be included in the next
> release?
>
> Iterator, resultset and statefull object are corner test for mocking
> libraries, but I think Mockito could gain visibility out of this. I
> am running a pilot project to include Mockito in our environment. When
> I asked a dude to tell me an object he would want me to mock in a
> presentation, is first thought was about ResultSet or an Iterator o
No, really, don't start there.
S.
On 17 Jun 2008, at 14:20, szczepiq wrote:
> My advice about mocking ResultSet: don't :). Few days ago my friend
> showed me a really nice implementation of hand made stub for
> ResultSet. It was based of 'fluent builder' pattern and it really
> looked very nice in test methods.
Steve Freeman
http://www.mockobjects.com
Winner of the Agile Alliance Gordon Pask award 2006