Gmock is getting complex

4 views
Skip to first unread message

Julien

unread,
Mar 1, 2009, 8:56:33 AM3/1/09
to gmock-dev
I've been looking at the way of implementing the mocking out method
from concrete object and it involve adding more complexity. And I
start seeing some complexity growing.

As part of issue-52 I was considering adding a new proxy meta class
that would decide if method need to be mocked or directly called to
the original object. Some complexity come to the fact that the current
MockProxyMetaClass is closely linked to the recording of expectation.
That what I'd like to change and reintroduce some concept of
MockInternal for that. I know we move away from it due to the horrible
_verify style of method but there might be other way for that. This
would mean refactoring the doInternal style which had complexity as
well.

I am thinking that the MPMC can find its associated MockInternal using
a map key on MPMC identity that could be store in the controller. From
what I can see this seems doable.

I am not sure I am very clear here but what's your feeling about it?

Johnny

unread,
Mar 1, 2009, 9:49:25 AM3/1/09
to gmoc...@googlegroups.com
My original thought of implementing this is: store the concrete object
in the MPMC; iterate all MPMCs and attach it to the concrete object if
it carrying one when entering the play closure; when findExpectation()
cannot find a matching expectation, invoke a passed in closure to invoke
the original implementation if the MPMC carrying a concrete object.

Here, invoking the original implements by delegating to the original
metaclass of that concrete object will be more complex but more
reasonable, while by delegating to the default metaclass of the class of
that concrete object (i.e. the adaptee in MPMC) will be easier.

Hope this can help you.

PS: I was also feeling that gmock is getting more complex while
implementing strict ordering and improving error messages.

在 2009-03-01日的 05:56 -0800,Julien写道:

Johnny Jian

unread,
Mar 1, 2009, 10:22:16 AM3/1/09
to gmock-dev
Aha, "iterate all MPMCs and attach it to the concrete object if it
carrying one when entering the play closure" can be done in MPMC.replay
(). "invoking the original implements by delegating to the original
metaclass of that concrete object will be more complex but more
reasonable", just setting MPMC.adaptee to the original metaclass of
that concrete object can solve the problem (set in replay() and
restore in reset()).

Then, it seems clear to me now :)

Julien Gagnet

unread,
Mar 1, 2009, 10:49:49 AM3/1/09
to gmoc...@googlegroups.com
If we consider the following example;

def tagLib = new TabLib()
def mockTagLib = mock(tagLib)
mockTagLib.link([:], "hello").returns("hello")
play {
assertEquals "hello", tagLib.sayHello([:])
}

where:
sayHello { attr ->
return link(attr, "hello")
}

We can't just change the adaptee inside the play closure. They should
be some logic that decide that:
link() is mocked
sayHello() call the real implementation

That's why I need a specialise ProxyMetaClass for that which will have
a reference to its MockInternal. I'll give a try to this
refactoring...



2009/3/1 Johnny Jian <Johnny...@gmail.com>:

Johnny

unread,
Mar 1, 2009, 11:12:02 AM3/1/09
to gmoc...@googlegroups.com
Because it cannot find an expectation matching sayHello(), so the
original metaclass will be invoked. I think it can be done in
MetaClassHelper.findExpectation():

static findExpectation(expectations, signature, message, arguments,
controller, invokeOriginal) {
def expectation =
controller.orderedExpectations.findMatching(signature) ?:
expectations.findMatching(signature)
if (expectation){
return expectation.answer(arguments)
} else if (invokeOriginal) {
return invokeOriginal()
} else {
controller.fail(message, signature)
}
}

Am I missing something?

在 2009-03-01日的 15:49 +0000,Julien Gagnet写道:

Julien Gagnet

unread,
Mar 1, 2009, 11:36:39 AM3/1/09
to gmoc...@googlegroups.com
I think the problem would be for error reporting. If I mock link()
mockTagLib.link([some: "attr]).returns("hello)

but call
mockTagLib.link([other: "attr"])
in the code under test. Then we won't get a nice error message
expected ... but was ...

2009/3/1 Johnny <johnny...@gmail.com>:

Johnny

unread,
Mar 1, 2009, 8:47:35 PM3/1/09
to gmoc...@googlegroups.com
What is the expected behavior here? It should throw an exception here,
right? Then I think we should discuss the behavior of mocking methods on
a concrete object.

Assume that we have:

class A {}
class B extends A {}
class C extends B {}

Then we mock:

def b = new B()
mock(something).method(b)

And we call:

something.method(b) // it is mocked
// but what about the following methods?
something.method(new Object())
something.method(new A())
something.method(new B())
something.method(new C())
something.method(new B(), new Object())

So which methods above should be failed and which else should invoke the
original implements?

在 2009-03-01日的 16:36 +0000,Julien Gagnet写道:

Julien

unread,
Mar 2, 2009, 2:34:32 AM3/2/09
to gmock-dev
I wasn't really thinking about inheritance here. I don't know what
should be the expected behavior for inheritance and I am not sure if
it's going to be really used.

It's more for the logic here:
if (expectation){
return expectation.answer(arguments)
} else if (invokeOriginal) {
return invokeOriginal()
} else {
controller.fail(message, signature)
}
we need more something like
} else if (invokeOriginal && !expecations.containMethodName
(methodName) {

where expectations is the expectation collection. That was the only
thing I was pointing.
> > 2009/3/1 Johnny <johnnyjia...@gmail.com>:
> > >> 2009/3/1 Johnny Jian <JohnnyJia...@gmail.com>:

Johnny

unread,
Mar 2, 2009, 5:52:34 AM3/2/09
to gmoc...@googlegroups.com
I agree that it is a rare case. It is complex to define the correct
behavior (correct type handling) and implement it unless the users
declare what the types of the parameters are.

So, let's just make it simple: if the method call has the same method
name and same number of parameters as some expectation, it is mocked,
otherwise it is not.

在 2009-03-01日的 23:34 -0800,Julien写道:

Julien Gagnet

unread,
Mar 2, 2009, 1:27:26 PM3/2/09
to gmoc...@googlegroups.com
I think I'll try to do something similar to the hashcode, tostring...
and only fail if some expectations has been setup on that particular
method. I hope we are not in a rush for 0.7 cause I might take my time
to do it but looking forward to it.

2009/3/2 Johnny <johnny...@gmail.com>:

Julien

unread,
Mar 3, 2009, 3:30:41 AM3/3/09
to gmock-dev
I've start moving some of the code from MPMC to MockInternal and found
this weird issue. If I change

Object invokeMethod(Class sender, Object receiver, String
methodName, Object[] arguments, boolean isCallToSuper, boolean
fromInsideClass) {
doInternal(controller) {
adaptee.invokeMethod(receiver, methodName, arguments)
} {
return mock.invokeMockMethod(sender, receiver, methodName,
arguments)
}
}

to
Object invokeMethod(Class sender, Object receiver, String
methodName, Object[] arguments, boolean isCallToSuper, boolean
fromInsideClass) {
return mock.invokeMockMethod(sender, receiver, methodName,
arguments)
}

I am having the testPassAMockObjectToAnotherButNotCalled that start to
fail. Somehow in the line 'mock1.is(mock2).returns(true)' mock2 is
seen as a recorder.

There a bit of magic happening here. Any idea how ?




On Mar 2, 6:27 pm, Julien Gagnet <julien.gag...@gmail.com> wrote:
> I think I'll try to do something similar to the hashcode, tostring...
> and only fail if some expectations has been setup on that particular
> method. I hope we are not in a rush for 0.7 cause I might take my time
> to do it but looking forward to it.
>
> 2009/3/2 Johnny <johnnyjia...@gmail.com>:

Johnny

unread,
Mar 3, 2009, 3:43:21 AM3/3/09
to gmoc...@googlegroups.com
That's one of the reasons why we need internal mode. When a mock is used
as a parameter of another mock's expectation, we need to do the
parameter checking in an internal mode, i.e. without mocking any methods
on that mock.

在 2009-03-03二的 00:30 -0800,Julien写道:

Julien

unread,
Mar 3, 2009, 2:12:02 PM3/3/09
to gmock-dev
Yes I've realised all that now, I was hoping to simplified that a bit
but with no luck. The problem I have with it is that it force us to
carry the controller everywhere. We'll live with it for the moment.

I did a bit of refactoring when introducing the MockInternal. It's
just moving stuff around but I can say that the unit test coverage
picked all the mistake I was doing which is good and reassuring.

Let me know what you think about it.

Johnny

unread,
Mar 3, 2009, 8:46:39 PM3/3/09
to gmoc...@googlegroups.com
I think we should first make it works and then improve it. Currently I
have no idea about how to get rid of the internal mode, and I realize
that this may make it harder to make gmock thread-safe.

在 2009-03-03二的 11:12 -0800,Julien写道:
Reply all
Reply to author
Forward
0 new messages