jumping656 / googlemock

Automatically exported from code.google.com/p/googlemock
BSD 3-Clause "New" or "Revised" License
0 stars 0 forks source link

need better support for partial ordering of expectations #50

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
JJ wrote:

I'd like to talk about the test sequencing features. As explained in
the Cookbook,
it's possible to place expectations into an arbitrary directed acyclic
graph in
their sequencing, in theory. However, I'm finding this sometimes
extremely
cumbersome, and occasionally impossible, in practice. Let me give some
examples:

Suppose that I have a simple mock class

class MockA: public AInterface
{
   MOCK_METHOD0(a, void());
   MOCK_METHOD0(b, void());
   MOCK_METHOD0(c, void());

   MOCK_METHOD0(final, void());
};

and I want to expect that all of a(), b() and c() are called in
unspecified order,
and then final() is called after all three of them, my understanding
is that my
only recourse is to specify the following:

MockA myMock;

Sequence s, t, u;

EXPECT_CALL(myMock, a()).InSequence(s);
EXPECT_CALL(myMock, b()).InSequence(t);
EXPECT_CALL(myMock, c()).InSequence(u);

EXPECT_CALL(myMock, final()).InSequence(s, t, u);

This is starting to get a bit unwieldy, and would only get more so as
the number
of expectations increased. More telling, though, is that this setup
requires
knowledge of exactly how many expectations are going to be in the
initial group before
the expectation for final() can be created, so that the correct number
of sequences
can be created. Unfortunately, I don't think this is always the case:
consider the
situation in which the group of expectations is being created by a
polymorphic or
templated function, such as the following:

struct Tester
{
   void setAllExpectations
   {
       MockA myMock;

       //How many sequences would I create here? We don't know how
many
       //expectations the virtual method is going to create, and we
can't even
       //*call* it without that information, because we'd have to
pass all the
       //sequences into it to replicate the previous code.

       setABCExpectations(myMock);

       EXPECT_CALL(myMock, final());
   }

protected:
   virtual void setABCExpectations(MockA& myMock) = 0;
};

Now, unless I've just missed a much more natural way to do what I want
to do there,
it's now impossible to create the desired ordering.

Has anyone else run into this situation? Is it worth adding
functionality to
enhance the ordering possibilities for expectations?

Thanks for your time,

JJ

One possible natural syntax for such an enhancement follows, provided
for the
purposes of discussion -- I don't claim to be sufficiently conversant
with the
internal code of Google Mock to know how difficult it would be to make
this
happen, though.

MockA myMock;

Sequence s;

{
   Group g(s);

   //alternatively an object of type InGroup could obviate the need
for the
   //InGroup clauses on the expectations, in the same way as
InSequence objects.

   EXPECT_CALL(myMock, a()).InGroup(g);
   EXPECT_CALL(myMock, b()).InGroup(g);
   EXPECT_CALL(myMock, c()).InGroup(g);
}

EXPECT_CALL(myMock, final()).InSequence(s);

Semantically, the above Group object would have to create some kind of
temporary
collection of Expectations that could be inserted in the sequence s
instead of
an individual expectation. The group would naturally be complete when
all expectations
within it were complete, and therefore only then could the call to
final() succeed.

------------------------------------------------------------------------

I wrote:

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.
- Show quoted text -

> One possible natural syntax for such an enhancement follows, provided
> for the
> purposes of discussion -- I don't claim to be sufficiently conversant
> with the
> internal code of Google Mock to know how difficult it would be to make
> this
> happen, though.
>
> MockA myMock;
>
> Sequence s;
>
> {
>    Group g(s);
>
>    //alternatively an object of type InGroup could obviate the need
> for the
>    //InGroup clauses on the expectations, in the same way as
> InSequence objects.
>
>    EXPECT_CALL(myMock, a()).InGroup(g);
>    EXPECT_CALL(myMock, b()).InGroup(g);
>    EXPECT_CALL(myMock, c()).InGroup(g);
> }
>
> EXPECT_CALL(myMock, final()).InSequence(s);
>
>
> Semantically, the above Group object would have to create some kind of
> temporary
> collection of Expectations that could be inserted in the sequence s
> instead of
> an individual expectation. The group would naturally be complete when
> all expectations
> within it were complete, and therefore only then could the call to
> final() succeed.

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

Original issue reported on code.google.com by zhanyong...@gmail.com on 5 Jun 2009 at 12:22

GoogleCodeExporter commented 8 years ago

Original comment by zhanyong...@gmail.com on 18 Aug 2009 at 6:58