This is the log of a sample project from a small band of software engineers eager to learn better ways of working and new technologies. We've decided to use .NET 3.0 to create a Battleships game.

The Quest For The Perfect Project

Wednesday 9 May 2007

Mocking helps test in isolation

As you are probably already aware, I've been spending most of my time expanding the domain classes that we've come up with. It's been a roller coaster ride going backwards and forwards over several ideas of how it's all implemented. I've actually made forward progress this week in that I'm stepping on territory that hasn't already been visited.

I now have what I see as the fundamentals behind the domain classes ironed out and I decided to write a few tests that exercised game play. Our Game class is somewhat simple at the moment [see figure 1] and at this moment in time we're not 100% sure on how the server will interact with the clients, though I suspect this will become more of an issue sooner rather than later.

public sealed class Game
{
    static Game theGame = null;

    readonly static object locker = new object();

    IList<Board> boards = new List<Board>(); 

    private int currentTurn;

    private IGameController gameController;

    private Game()
    {
    }

    public static Game TheGame
    {
        get
        {
            if (theGame == null)
            {
                lock (locker)
                {
                    if (theGame == null)
                    {
                        theGame = new Game();
                    }
                }
            }
            return theGame;
        }
    }

    public IGameController GameController
    {
        get { return gameController; }
        set { gameController = value; }
    }

    public Board this[Player player]
    {
        get
        {
            foreach (Board board in boards)
            {
                if (board.Player == player)
                {
                    return board;
                }
            }
            return null;
        }
    }

    public void AddBoard(Board board)
    {
        boards.Add(board);
    }

    public int NumberOfPlayers()
    {
        return boards.Count;
    }

    public void NextTurn()
    {
        if (currentTurn >= boards.Count)
        {
            // Reset to player 1 again.
            currentTurn = 0;
        }
        Board playersBoard = boards[currentTurn];
        Attack attack = gameController.TakeTurn(playersBoard.Player);

        Board targetsBoard = this[attack.Target];
        bool result = targetsBoard.ProcessAttack(attack);
        currentTurn++;
    }

    public static void Reset()
    {
        lock (locker)
        {
            theGame = null;
        }
    }
}

Figure 1.

Whilst I'm in the domain area all that I am interested in at the moment is my domain objects. I'm also trying to be truly Agile with our design in that, yes I'm aware that we'll need some form of communication layer and interface into that layer, but at the moment it's not essential that I know the nitty gritty of how it will be implemented. I just assumed that I'd have some interface, with a mechanism for taking a turn. I'd expect this interface to undergo changes when we actually get to the design/implementation of that area.

public interface IGameController
{
    Attack TakeTurn(Player target);
}

Figure 2.

This issue in the past would have caused us problems at this early stage in development when it comes to testing the game play. We could have written a test stub class that we could talk to that provided us with responses to exercise the object. These days you'll often hear people refer to mocking instead. Mocking is not an easy concept to grasp - it took me a while and it's probably a lot harder to explain. We're using Rhino.Mocks for mocking as it is probably the closest mocking library to the one we've used when developing Java. At first I wasn't entirely sure how I was going to test the game play and my first attempt resulted in me writing the steps that I wanted to do, along with what I'd expect to be returned as comments. I then went to bed...

The following evening, I started to create the mock with a little help from some sample code that Jon happened to produce for a presentation to our colleagues on mocking using Rhino.Mocks, figure 3 shows the test in all it's glory.

[Test]
public void VerifyMultipleShipHealthBars()
{
    // Test the game with 3 separate attacks to only 2 targets.
    // Create and program the mocks to do this.
    MockRepository factory = new MockRepository();
    IGameController controller = factory.CreateMock<IGameController>();

    Expect.Call(controller.TakeTurn(evan))
          .Return(new Attack(evan, emma, 2, 3)); // should be a hit for ship1
    Expect.Call(controller.TakeTurn(emma))
          .Return(new Attack(emma, caroline, 3, 2)); // should be a miss
    Expect.Call(controller.TakeTurn(caroline))
          .Return(new Attack(caroline, emma, 2, 3)); // should be a hit for ship1

    factory.ReplayAll();

    // Create the component under test (CUT) and proceed with behaviour.
    Game game = Game.TheGame;
    game.AddBoard(evansBoard);
    game.AddBoard(emmasBoard);
    game.AddBoard(carolinesBoard);

    game.GameController = controller;

    game.NextTurn();
    game.NextTurn();
    game.NextTurn();

    Assert.AreEqual(2, ship1.GetHealth(evan));
    Assert.AreEqual(2, ship1.GetHealth(caroline));

    // Verify that the mock executed as expected.
    factory.VerifyAll();
}

Figure 3.

Mocking will only get you so far and this test is far from complete because it's now highlighted the need to move onto the IGameController interface. As you can see from the NextTurn method in the Game class, we're losing the result from the ProcessAttack method call. This return value would be valuable to the client so that it could update the EnemyBoard for the player. Although the Game.NextTurn() is incomplete, it's still functioning at the moment and it has helped immensely to have a unit test mocking the IGameController concept at this early stage in development. It served it's purpose as it found one or two bugs in my Board logic.

I envisage my next steps to be designing the GameController interface some more, looking at the possibility of having the following calls to complete the next turn functionality.

Figure 4.

Once this communication has been established, I can then revisit my unit test around gameplay and modify that accordingly to exercise the game class with the expanded IGameController implementation. It was however a great exercise and it gave me a chance to play with mocking in .NET.

7 Comments:

your singleton is a bit of a mess of two ideas....

a static constructor is guaranteed by the framework to be only accessed by one thread, so you dont need your object locking
actually, its worse than that, you dont even neeed the singleton! :-)

Kill the singleton, change the tests to use a game object.

create the game object in your setup.
Ooooo...

Theres a whole bunch of refactoring I want to do on the code!

(I was looking around for WPF examples.... )

also it would be cool if you guys put a link to the source forge on the blog
I don't think it's a mess of two ideas, although it's not the implementation I'd have chosen.

The static constructor doesn't (currently) instantiate the game - only the first call to the property does. So with the current type of laziness, the lock *is* needed. If Emma had chosen to use the static constructor, it would potentially have made the game initialise itself earlier, and the static constructor would then have been enough. Personally that's the way I'd have gone, but that code needs more modification than just removing the locking.
Again, I agree that singletons should in general be avoided. I haven't looked closely enough at the rest of Emma's code to see whether or not it should be removed here - we'll see as we (gradually) progress.
Link to source forge: it's on the first post in the blog :)
Thanks for the comments. I'm not sure why I chose to model the Singleton - it's a frowned upon design pattern because 90% of the time it's implemented incorrectly. I probably don't really need a singleton, it could just be one instance of the game as you say that is initialised at the beginning and then killed at the end of each test.

Just one point though... I don't see a static constructor in my code. I just happened to be at a conference last week and this design patterns session I went to studied the Singleton for far too long and they went over two methods of creating a Singleton.

1) Using the static constructor (Jon's right about it being instantiated early on)

2) Going for the lazy initialisation way that I went for with the double checking and locking in a Property that will call the private constructor to intialise the Singleton instance.

This class is far from complete and I'm sure most of the code will end up being refactored out of it anyway.. One of my earlier posts went on about how much time I seem to spend refactoring the code I've already written :).

Add a comment