views:

471

answers:

5

At the moment I have:

    [Test]
    public void DrawDrawsAllScreensInTheReverseOrderOfTheStack() {
        // Arrange.
        var screenMockOne = new Mock<IScreen>();
        var screenMockTwo = new Mock<IScreen>();
        var screens = new List<IScreen>();
        screens.Add(screenMockOne.Object);
        screens.Add(screenMockTwo.Object);
        var stackOfScreensMock = new Mock<IScreenStack>();
        stackOfScreensMock.Setup(s => s.ToArray()).Returns(screens.ToArray());
        var screenManager = new ScreenManager(stackOfScreensMock.Object);
        // Act.
        screenManager.Draw(new Mock<GameTime>().Object);
        // Assert.
        screenMockOne.Verify(smo => smo.Draw(It.IsAny<GameTime>()), Times.Once(),
            "Draw was not called on screen mock one");
        screenMockTwo.Verify(smo => smo.Draw(It.IsAny<GameTime>()), Times.Once(), 
            "Draw was not called on screen mock two");
    }

But the order in which I draw my objects in the production code does not matter. I could do one first, or two it doesn't matter. However it should matter as the draw order is important.

How do you (using Moq) ensure methods are called in a certain order?

Edit

I got rid of that test. The draw method has been removed from my unit tests. I'll just have to manually test it works. The reversing of the order though was taken into a seperate test class where it was tested so it's not all bad.

Thanks for the link about the feature they are looking into. I sure hope it gets added soon, very handy.

+2  A: 

Have a look at this blog post, it may solve your problem.

Lucero
Couldn't get this to work in my case, I couldn't use a queue in exchange of the array. Doesn't matter though now. See edit.
Finglas
Nice link, though!
TrueWill
+1  A: 

It appears that it's not currently implemented. See Issue 24: MockSequence. This thread discusses the issue.

You might consider revising your tests, though. I generally feel that testing order leads to fragile tests, as it's often testing implementation details.

EDIT: I'm not sure that this addresses the OP's question. Lucero's answer may be more helpful.

TrueWill
A: 

Otherwise you could have used the Callback functions and increment/store a callIndex value.

//Daniel

Daniel
+1  A: 

I recently created Moq.Sequences which provides the ability to check ordering in Moq. You may want to read my post that describes the following:

  • Supports method invocations, property setters and getters.
  • Allows you to specify the number of times a specific call should be expected.
  • Provides loops which allow you to group calls into a recurring group.
  • Allows you to specify the the number of times a loop should be expected.
  • Calls that are expected to be called in sequence can be inter-mixed with calls that are expected in any order.
  • Multi-threaded support.

Typical usage looks like:

[Test]
public void Should_show_each_post_with_most_recent_first_using_sequences()
{
    var olderPost = new Post { DateTime = new DateTime(2010, 1, 1) };
    var newerPost = new Post { DateTime = new DateTime(2010, 1, 2) };
    var posts = new List<Post> { newerPost, olderPost };

    var mockView = new Mock<BlogView>();

    using (Sequence.Create())
    {
        mockView.Setup(v => v.ShowPost(newerPost)).InSequence();
        mockView.Setup(v => v.ShowPost(olderPost)).InSequence();

        new BlogPresenter(mockView.Object).Show(posts);
    }
}
Declan Whelan
A: 

From the original post I could assume that the testing method do the following operations call:

var screenOne = new Screen(...);
var screenTwo = new Screen(...);
var screens = new []{screenOne, screenTwo};
var screenManager = new ScreenManager(screens);
screenManager.Draw();

Where 'Draw' method implementation is something like this:

public class ScreenManager
{
    public void Draw()
    {
        _screens[0].Draw();
        _screens[1].Draw();
    }
}

From my perspective, if the call order is very important then additional structure (that describe sequence) should be introduced into system.

The simplest implementation: each screen should know his subsequent element and call its Draw method after drawing himself:

// 1st version
public class Screen(Screen screenSubSequent)
{
    private Screen _screenNext;
    public Screen(Screen screenNext)
    {
        _screenNext=screenNext;
    }
    public void Draw()
    {
        // draw himself
        if ( _screenNext!=null ) _screenNext.Draw();
    }
}

public class ScreenManager
{
    public void Draw()
    {
        _screens[0].Draw();
    }
}

static void Main()
{
    var screenOne = new Screen(null, ...);
    var screenTwo = new Screen(screenOne, ...);
    var screens = new []{screenOne, screenTwo};
    var screenManager = new ScreenManager(screens);
}

From the one point, each Screen element should know a little about another one. This is not always good. If so: you can create some class like 'ScreenDrawer'. This object will store own screen and subsequent screen (probably inherit him from Screen class. Using other worlds: 'ScreenDrawer' class describes system structure. Here is a simplest scenario of implementation:

// 2nd version
public class ScreenDrawer
{
    private Screen _screenNext;
    public ScreenDrawer(Screen screenNext, ...) : base (...)
    {
        _screenNext=screenNext;
    }
    public void Draw()
    {
        // draw himself
        if ( _screenNext!=null ) _screenNext.Draw();
    }
}

public class ScreenManager
{
    public void Draw()
    {
        _screens[0].Draw();
    }
}

static void Main()
{
    var screenOne = new ScreenDrawer(null, ...);
    var screenTwo = new ScreenDrawer(screenOne, ...);
    var screens = new []{screenOne, screenTwo};
    var screenManager = new ScreenManager(screens);
}

2nd method introduce additional inheritance, but doesn't required Screen class to know about his subsequence element.

Summary: both methods do sub-sequential calls and doesn't require 'sequence' testing. Instead they require testing if current 'screen' calls another one and testing if 'ScreenManager' calls 'Draw' method of the 1st element in sequence.

This approach:

  1. More testable (can be implemented using most of testing framework without necessity to support 'sequence testing');
  2. More stable (nobody can easily change a sequence: hi will need not only update the source code, but also update few tests);
  3. More object oriented (you are working with object, not with abstract entities like 'sequence');
  4. As a result: much more supportable.

Thanks.

Budda