One alternative would be to forward the first three calls to a
different expectation:
EXPECT_CALL(myMock, a())
.WillOnce(Invoke(&check, &CheckPoint::Check));
EXPECT_CALL(myMock, b())
.WillOnce(Invoke(&check, &CheckPoint::Check));
EXPECT_CALL(myMock, c())
e.WillOnce(Invoke(&check, &CheckPoint::Check));
{
InSequence s;
EXPECT_CALL(check, Check()).Times(3);
EXPECT_CALL(myMock, final());
}
As you've defined "setABCExpectations()" it's probably impossible, as
you haven't provided a channel for more information to go down or up.
But, if you change it to:
virtual int setABCExpectations(MockA& myMock, CheckPoint& check);
then you should have no trouble using the pattern above. You could
replace CheckPoint with a class that would do the bookkeeping itself,
and save you from having to count the number of calls and return it.
On Thu, Jun 4, 2009 at 3:18 AM, JJ <jo...@autonomy.com> wrote:
>
> Hi all,
>
> First off, I'd just like to say that Google Mock is great. It's made
> my testing
> life much easier. Thanks!
Thanks for the feedback!
I agree that your use case is not well supported right now (you can
use the trick Chris suggested, but it doesn't scale well when your
expectations are more complex. A more natural encoding of your intent
will make the test much easier to read.).
Our philosophy is to keep Google Mock conceptually as simple as
possible. Therefore we tend to wait for actual needs to come up
before we implement something. That way we can be more sure that our
design does solve the user's problem, and that we don't bloat Google
Mock with "features" that don't match the reality.
Something like this might be made to work. However, it's unclear to
me what the relationship between groups and sequences should be. The
"Group g(s);" syntax suggests that there's some connection between g
and s, but what is it? I can understand it in your specific example,
but what about the general case? How do you associate one group with
multiple sequences? And how do you associate multiple groups with one
sequence? What's the semantics of these combinations? Is the
semantics sound? In the end, it can get muddy quickly.
As you stated, the problem you are having is that the InSequence()
syntax requires you to know the number of sequences when you *write*
the code, which is not always possible. We can fix this by allowing
InSequence() (or use a different name like InSequenceSet()) to accept a
container of sequences. Then the above program can be written as:
MockA myMock;
SequenceSet ss;
EXPECT_CALL(myMock, a()).InSequence(ss.AddNew());
EXPECT_CALL(myMock, b()).InSequence(ss.AddNew());
EXPECT_CALL(myMock, c()).InSequence(ss.AddNew());
EXPECT_CALL(myMock, final()).InSequenceSet(ss);
Notes:
- "Set" emphasizes that the order of the elements is unimportant.
- ss.AddNew() creates a new Sequence, adds it to ss, and returns the
Sequence.
- An expectation can accepts multiple InSequence()s and/or multiple
InSequenceSet()s.
It's easy to see that the semantics of InSequenceSet(ss) is sound, as
it can be viewed as a syntactic sugar of InSequence(s1, ..., sn) where
s1, ..., and sn are the members of ss. Being a syntactic sugar also
means a user can learn this construct easily.
Thoughts?
--
Zhanyong
One more note:
- We provide SequenceSet as a convenience. However, the user is not
restricted to it. You can pass any STL-style containers to
InSequenceSet().
>
> It's easy to see that the semantics of InSequenceSet(ss) is sound, as
> it can be viewed as a syntactic sugar of InSequence(s1, ..., sn) where
> s1, ..., and sn are the members of ss. Being a syntactic sugar also
> means a user can learn this construct easily.
>
> Thoughts?
>
> --
> Zhanyong
>
--
Zhanyong
One nice thing about the sequence abstraction is that it guarantees
(by construct) that the graph is acyclic. In other words, it prevents
the user from making the mistake of defining a cyclic ordering. I
would like whatever constructs we add to have this property too.
IIUIC, the following code using Group:
Sequence s;
Group g(s);
EXPECT_CALL(mock, a()).InGroup(g);
EXPECT_CALL(mock, b()).InSequence(s);
EXPECT_CALL(mock, c()).InGroup(g);
would result in a() and c() being in the same group g, and g -> b() ->
g. This is a cyclic graph. So I guess we need to impose some
restrictions on the usage of groups.
These are excellent points. I don't have a good answer yet, but will
keep thinking about it and update the list if I make any progress.
I'd encourage other people to do the same too. Thanks,
>
> --JJ
>
>>
>> --
>> Zhanyong
>
--
Zhanyong
To say that B(), C(), and D() must be after A():
Expectation a = EXPECT_CALL(foo, A());
EXPECT_CALL(foo, B()).After(a);
EXPECT_CALL(foo, C()).After(a);
EXPECT_CALL(foo, D()).After(a);
To say that E() must be after B(), C(), and D():
ExpectationSet es;
es += EXPECT_CALL(foo, B());
es += EXPECT_CALL(foo, C());
es += EXPECT_CALL(foo, D());
EXPECT_CALL(foo, E()).After(es);
To say that X(), Y(), and Z() must be after B(), C(), and D():
ExpectationSet es;
es += EXPECT_CALL(foo, B());
es += EXPECT_CALL(foo, C());
es += EXPECT_CALL(foo, D());
EXPECT_CALL(foo, X()).After(es);
EXPECT_CALL(foo, Y()).After(es);
EXPECT_CALL(foo, Z()).After(es);
Notes:
- A variable of type Expectation identifies an EXPECT_CALL(). To bind an
Expectation variable x with an EXPECT_CALL(), just write "x =
EXPECT_CALL(...)...;"
- An ExpectationSet is a set of Expectation values. The += operator
can be used to add an Expectation to an ExpectationSet.
- EXPECT_CALL() accepts a new clause .After(e1, ..., en), where each e
is either an Expectation or an ExpectationSet. This adds the
constraint that the current expectation can be matched only after
all of e1, ..., and en have been matched.
- We'll continue to allow the .InSequence() syntax, which can be
viewed as a syntactic sugar for .After(). Suppose we have two
EXPECT_CALLs in the same sequence s:
EXPECT_CALL(foo, X()).InSequence(s);
...
EXPECT_CALL(foo, Y()).InSequence(s);
we can always rewrite them as:
Expectation e = EXPECT_CALL(foo, X());
...
EXPECT_CALL(foo, Y()).After(e);
- The ordering is still guaranteed to be acyclic by construct. In
EXPECT_CALL(...).After(e1, ..., en);
e1, ..., and en can only reference EXPECT_CALLs defined *before* the
current one. Hence a cycle is impossible.
Thoughts?
2009/6/8 Zhanyong Wan (λx.x x) <w...@google.com>:
--
Zhanyong
Thanks for the feedback and great suggestions. I like them.
Since the improvements you suggested are nice to have but not
indispensable, I'd like to implement the basic constructs first, see
how people are using them, and then decide what to do with the
improvements based on more user feedback. Since some people may have
got lost in this discussion, I'll start a new thread to solicit
comments on the design. Thanks,
--
Zhanyong