Defining expectations' sequence

1,258 views
Skip to first unread message

eugene....@gmail.com

unread,
Mar 12, 2008, 2:46:50 PM3/12/08
to Moq Discussions
Hi guys! Thanks for a greate library, keep doing a great job!

I'm using MOQ a lot and it covers most of the use cases I have when
testing. Recently I came across a scenario where it feels some extra
help from MOQ will be appropriate. Consider the following scenario:

interface IFile {
void Open();
..
void Close();
}

class Target() {
public void UseFile(IFile file) {}
}

When testing the UseFile(IFile file) implementation my mock may look
like this:
var mock = new Mock<IFile>();
mock.Expect((f)=>f.Open()).AtMostOnce();
mock.Expect((f)=>f.Close()).AtMostOnce();

Target target = new Target();
target.UseFile(mock.Object);
mock.VerifyAll();

The problem with the following code that there is no way for me to
express that Open() is expected before Close(); I can use Callback()
and enforce the logic manually, but there should be a better solution
from the Moq.

Please give it a thought. Thanks!

-Eugene

Brian J. Cardiff

unread,
Mar 12, 2008, 6:41:58 PM3/12/08
to moq...@googlegroups.com
Eugene,

As you point at the end of your message, you can do what you want with a bunch of Callbacks. Ugly code, but it can be done.

IMO a better approach would be to create some extensions on top of Moq to get better test code for that scenario, do you agree?

In that direction I was able to do a partial solution. You can look at my personal sandbox at http://<server>/svn/sandbox/trunk/MoQSamples/ with <server>=pixpex.no-ip.com under the Extensibility project.

The solution is partial since it only supports ordered expectations on void methods, and don't use additional callback or throws. Maybe the interface I started is not the right way, but at least is one direction.

The following test passed:

public interface IFoo
{
  void Method1();
  void Method2();
  void Method3();
  void Method4();
}

[Test]
public void ManyWellOrderedCalls()
{
  mocked = new Mock<IFoo>();
  mocked
    .ExpectFirst(x => x.Method1())
    .ExpectAfter(x => x.Method2())
    .ExpectAfter(x => x.Method3())
    .ExpectAfter(x => x.Method4());

  mocked.Object.Method1();
  mocked.Object.Method2();
  mocked.Object.Method3();
  mocked.Object.Method4();
}

[Test]
[ExpectedException]
public void WrongOrderShouldThrowException()
{
  mocked = new Mock<IFoo>();
  mocked
    .ExpectFirst(x => x.Method1())
    .ExpectAfter(x => x.Method2())
  mocked.Object.Method2();
--
Brian J. Cardiff
bcardiff(?)gmail.com
.

Daniel Cazzulino

unread,
Mar 12, 2008, 10:05:25 PM3/12/08
to moq...@googlegroups.com
I wonder why you didn't just use your private branch on Moq's SVN?

Brian J. Cardiff

unread,
Mar 13, 2008, 7:55:59 AM3/13/08
to moq...@googlegroups.com
Just because it was easier for me yesterday.
Depending on feedback and some spike I would like to do, I will start an extensibility private branch.

eugene....@gmail.com

unread,
Mar 13, 2008, 9:01:03 AM3/13/08
to Moq Discussions
Brian,

The approach with ExpectFirst(), ExpectNext() is viable, but I can
suggest a more streamlined and flexible one, based on external
coordinator. Something like:

MockSequence sequence = new MockSequence();
mocked = new Mock<IFoo>();
mocked2 = new Mock<IFoo>();

mocked.InSequence(sequence).Expect(x => x.Method1()));
mocked.InSequence(sequence).Expect(x => x.Method2()));
mocked.Expect(x => x.Method3())); // this one is not participating in
sequence check
mocked.InSequence(sequence).Expect(x => x.Method4()));

mocked2.InSequence(sequence).Expect(x => x.Method1()));

The expected sequence is now mocked.Method1, mocked.Method2,
mocked.Method4, and mocked2.Method1
So you can (if you want) specify sequence across multiple mocks, as
well as within the same mock. You can also have an expectation
participate in multiple sequences.

Thanks!
-Eugene



On Mar 13, 7:55 am, "Brian J. Cardiff" <bcard...@gmail.com> wrote:
> Just because it was easier for me yesterday.
> Depending on feedback and some spike I would like to do, I will start an
> extensibility private branch.
>
> On Thu, Mar 13, 2008 at 12:05 AM, Daniel Cazzulino <dan...@cazzulino.com>
> wrote:
>
>
>
>
>
> > I wonder why you didn't just use your private branch on Moq's SVN?
>
> > On Wed, Mar 12, 2008 at 8:41 PM, Brian J. Cardiff <bcard...@gmail.com>
> > wrote:
>
> > > Eugene,
>
> > > As you point at the end of your message, you can do what you want with a
> > > bunch of Callbacks. Ugly code, but it can be done.
>
> > > IMO a better approach would be to create some extensions on top of Moq
> > > to get better test code for that scenario, do you agree?
>
> > > In that direction I was able to do a *partial* solution. You can look at
> > > my personal sandbox at http://<server>/svn/sandbox/trunk/MoQSamples/ with
> > > <server>=pixpex.no-ip.com under the Extensibility project.
>
> > > The solution is *partial* since it only supports ordered expectations on
> .- Hide quoted text -
>
> - Show quoted text -

Brian J. Cardiff

unread,
Mar 13, 2008, 9:12:00 AM3/13/08
to moq...@googlegroups.com
Ok, that is more flexible. Did you have a scenario where that is needed?

First I imagine a TranslatorFixture where you want to test that the information is first retrieved from the Source and stored in the Target, but I would prefer to do it without forcing the sequence. So, do you have another scenario?

eugene....@gmail.com

unread,
Mar 13, 2008, 10:03:11 AM3/13/08
to Moq Discussions
My main scenario is testing a publish/subscribe framework:

I have a market data soure class (test target) that can be given one
or more subscribers (mocked). In the test I want to verify that
subscribers are called back in the order in which they subscribed (or
in any other order that is defined by priority rules):

var s1 = new Mock<ISubscriber>();
var s2 = new Mock<ISubscriber>();

MarketData target = new MarketData();
target.Subscribe(s1.Object);
target.Subscribe(s2.Object);

MockSequence priorityRules = new MockSequence();
s1.InSequence(priorityRules).Expect((s)=>s.OnNewPrice(100)).AtMostOnce();
s2.InSequence(priorityRules).Expect((s)=>s.OnNewPrice(100)).AtMostOnce();
target.SimulatePriceEvent(100);

Brian J. Cardiff

unread,
Mar 24, 2008, 1:45:49 AM3/24/08
to moq...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages