No, there is such feature in Mockito. You have to either return value
or throw an exception. Can you please submit a sample of the code
under test so that we can generalize the scenario and evaluate adding
new feature?
Based on my observations of large codebases I was a bit scared of the
way IAnswer was used (e.g. there were better and cleaner ways of
proving that things work). That's why it didn't make it to the API.
As usual, you may consider rolling your own hand written mock to keep
code clean :)
Looking forward to seeing a bit more sample code.
Cheers,
Szczepan Faber
>If you're still interested I can provide some code
>later.
I will find a sample useful so if it's not a hassle for you...
Cheers,
Szczepan Faber
S.
On 12 Apr 2008, at 23:33, szczepiq wrote:
>
> I'm glad you considered using own mocks. Regardless of any mocking
> tools, there is always a place for hand written mocks.
>
>> If you're still interested I can provide some code
>> later.
>
> I will find a sample useful so if it's not a hassle for you...
Steve Freeman
http://www.mockobjects.com
Winner of the Agile Alliance Gordon Pask award 2006
Actually, I don't remember writing a mock by hand since we moved to
Mockito. However before that, devs have been writing mocks to avoid
some of the side-effects of existing mock libraries. That's why I
kind of believe that if using mocking library gives me less readable
code, less readable errors or fragile tests then I roll my own mocks.
On the other hand, I succesfully avoid rolling own mocks by writing
code that is easily testable by Mockito.
Cheers,
Szczepan Faber
S
On 16 Apr 2008, at 19:07, szczepiq wrote:
>> Really? I haven't had to write one in years.
>
> Actually, I don't remember writing a mock by hand since we moved to
> Mockito. However before that, devs have been writing mocks to avoid
> some of the side-effects of existing mock libraries. That's why I
> kind of believe that if using mocking library gives me less readable
> code, less readable errors or fragile tests then I roll my own mocks.
> On the other hand, I succesfully avoid rolling own mocks by writing
> code that is easily testable by Mockito.
Steve Freeman
-inability to test what I want
-overspecified tests
-unreadable code (has anyone ever tried to answer simple question: why
'mocky' tests look so different from 'normal' tests)
-fragile tests
-unnatural TDD style
-difficult to learn (some)
-obscure verification errors
That's enough for many teams to consciously choose *not to use them*.
And yes, I agree: mocking / mocking libraries really not supposed to
be that complicated.
Cheers
Szczepan Faber
From your example I don't quite get where is the problem with missing
IAnswer interface. Here is what I did to test cage() method:
static class Zoo {
public void cage(Animal animal) {
// Need different behavior for elephants and monkeys
AnimalVisitor v = new AnimalVisitor() {
public void visitMonkey(Monkey monkey) {
monkey.setName("Bernard");
}
public void visitElephant(Elephant elephant) {
elephant.setAge(200);
}
};
animal.accept(v);
}
}
@Test
public void shouldCageMonkey() {
Zoo zoo = new Zoo();
MonkeyImpl m = new MonkeyImpl();
zoo.cage(m);
assertEquals("Bernard", m.getName());
}
@Test
public void shouldCageElephant() {
Zoo zoo = new Zoo();
ElephantImpl e = new ElephantImpl();
zoo.cage(e);
assertEquals(200, e.getAge());
}
Cheers,
Szczepan Faber
If Moneky and Elephant are hard to setup and maintain I would
probably: #1 make them easy to setup (e.g. builders for test
purposes), or #2: maintain examples of Animals (e.g. reference data)
for test purposes) or #3 mock them as you mentioned:
static class Zoo {
public void cage(Animal animal) {
// Need different behavior for elephants and monkeys
AnimalVisitor v = new AnimalVisitor() {
public void visitMonkey(Monkey monkey) {
monkey.haveBananas(2);
}
public void visitElephant(Elephant elephant) {
elephant.haveNuts(20);
}
};
animal.accept(v);
}
}
@Test
public void shouldCageMonkey() {
Zoo zoo = new Zoo();
MonkeyImpl m = new MonkeyImpl();
zoo.cage(m);
verify(m).haveBananas(2);
}
@Test
public void shouldCageElephant() {
Zoo zoo = new Zoo();
ElephantImpl e = new ElephantImpl();
zoo.cage(e);
verify(e).haveNuts(20);
}
So then, where in your example would you use generic IAnswer interface
for describing responses?
One thought about your exemplary code:
stub(e.getAge()).toReturn(200);
assertEquals(200, e.getAge());
Above assertion doesn't make much sense - it's testing Mockito framework...
Cheers,
Szczepan Faber
Mockito primary feature is to test interaction. Like any other
"mocking" library it has to provide mock/stub functionality to satisfy
certain interaction testing cases. Mockito, however, tries to keep
mocking/stubbing functionality as simple as possible.
What I see in your examples is, that you don't use Mockito to test
interaction, but you are using stubbing feature, which is to me side
effect of the interaction testing library.
The last example szczepiq provided, proves Zoo.cage interacts with
Monkey.haveBananas. Isn't it what you want to test ?
> static class Zoo {
> public void cage(Animal animal) {
> // Need different behavior for elephants and monkeys
> AnimalVisitor v = new AnimalVisitor() {
> public void visitMonkey(Monkey monkey) {
> monkey.haveBananas(2);
> }
>
> public void visitElephant(Elephant elephant) {
> elephant.haveNuts(20);
> }
> };
>
> animal.accept(v);
> }
> }
>
> @Test
> public void shouldCageMonkey() {
> Zoo zoo = new Zoo();
> Monkey m = mock(Monkey.class);
> zoo.cage(m);
> verify(m).haveBananas(2);
> }
>
Cheers,
Igor
Here is the test I would write. If you prefer to use IAnswer
interface, please write us few lines of code with theoretical test
implementation so we can compare both solutions.
This is my test:
public static class Zoo {
static final class Feeder implements AnimalVisitor {
public void visitMonkey(Monkey monkey) {
monkey.haveBananas(2);
}
public void visitElephant(Elephant elephant) {
elephant.haveNuts(20);
}
}
public void cage(Animal animal) {
AnimalVisitor v = new Feeder();
animal.accept(v);
}
}
Zoo zoo = new Zoo();
Zoo.Feeder f = new Zoo.Feeder();
@Test
public void shouldCageAnimal() {
Animal a = mock(Animal.class);
zoo.cage(a);
verify(a).accept(isA(Zoo.Feeder.class));
}
@Test
public void shouldFeedMonkey() {
Monkey m = mock(Monkey.class);
f.visitMonkey(m);
verify(m).haveBananas(2);
}
@Test
public void shouldFeedElephant() {
Elephant e = mock(Elephant.class);
f.visitElephant(e);
verify(e).haveNuts(20);
}
Cheers,
Szczepan Faber
Since I'm a fan of hand made mocks I would rather go for something like this:
public void testPingTimeout()
{
MockRemoteService remoteService = new MockRemoteService();
remoteService.makeUnreachable();
PingService pingService = new PingService();
pingService.setRemoteService(remoteService);
pingService.setTimeout(TIMEOUT);
pingService.doPing();
Thread.sleep(TIMEOUT * 2);
remoteService.makeReachable();
assertTimeoutReceived();
}
instead of IAnser-style:
public void testPingTimeout()
{
final Semaphor flag = new Semaphore(0);
RemoteService mockService = mock(RemoteService.class);
stub(mockService.ping()).toReturn(new IAnswer<Integer>()
{
public Integer answer()
{
flag.acquire();
return 1;
}
});
PingService pingService = new PingService();
pingService.setRemoteService(mockService);
pingService.setTimeout(TIMEOUT);
pingService.doPing();
Thread.sleep(TIMEOUT * 2);
flag.release();
assertTimeoutReceived();
}
The glaring benefit of hand made mock is very good test method
readability. More lines of code with the implementation of
MockRemoteService is an acceptable trade-off but it really depends on
how many test methods use MockRemoteService. If many tests use it then
LOC can go down because there will be less anonymous inner IAnswers.
>I am currently using a hand-written mock instead, but it bloats the
>test code as the service interface has many methods
Would you prefer hand-made mock over IAnswer if the service interface
didn't have many methods?
>Sometimes the large interface can (and indeed should) be
>broken up, but this is not always practical or desirable.
I was about suggest to break up the interface. Also, you can create
'Empty implementation' that can be subclassed easily without
implementing loads of irrelevant methods. However, as you say,
sometimes it might not practical or desirable. Although I'm not keen
on IAnswer feature (and I will never use it :-) I take your points and
I am thinking about including it in Mockito (can I have a patch,
please?).
As far as new verification mode is concerned (Felix' idea) - I'll
think about exposing verification mode so that it can be implemented
by clients.
Thank you guys for your suggestions!
Szczepan Faber
you could always use jMock2 for this test, which includes all this
functionliaty.
S.
Cheers ;)
Szczepan Faber
For the record, in jMock we have an 'allowing' clause that is the
equivalent of a stub.
> 2) We already use two mocking libraries (including mockito): adding a
> third is over the top in my opinion. If I could remove the original
> mocking library (inferior to both jMock2 and mockito), then it would
> be another story.
point taken...
Just out of interest, what's the inferior lib?
Cheers,
Szczepan
S.