Learning Unit Testing III – Emergent Design

So having seen the answers on my own StackOverflow question on TDD Design, I’ve decided to go ahead with the ‘emergent design’ crowd and see what happens. It appears that the refactoring and mid-stream redesigning is an integral part of the TDD process. It’ll all, of course, be described here (the process might be a little bit stream-of-consciousness) as I go through my design decisions ‘out loud’).

I got up to the end of page 9 last time, about to start on the Movement section. In keeping with the single responsibility principle, I’ll be putting movement logic in it’s own class. Movement happens in a strict order – all chargers are declared and moved first, then any compulsory moves are made, and finally ‘everything else’ movement. This would be represented in the MovementManager class as having an internal phase structure, just like the GameManager.

The question is, where should this be called from? The decision to stop moving chargers and move onto the next sub-phase is a player choice, therefore a user interface trigger (just as IncrementPhase). It is not something that can be automated or inferred. Should the IncrementPhase method (and associated fields) be moved out into a TurnManager class which is owned by GameManager – GameManager can then expose valid actions based on what phase and whose turn it is. Would that even need to be moved out into another class – if I am deciding actions based on what the GameManager will expose to a user interface, the turn logic can remain in GameManager.

Alternatively, the MovementManager can broadly restrict actions based on the properties of it’s parent (GameManager) and regulate it’s own, internal restrictions based on sub-phase and a variation of that logic. This seems like the simplest solution – I can raise a custom exception if a method is called on the MovementManager that is invalid (wrong sub-phase, or wrong phase entirely). Time for a new cl- uh, test class, obviously. Some of the tests can be cribbed from the existing GameManagerTests, but there’s no real worry about whose turn it is.

[TestClass]
public class MovementManagerTests
{
[TestMethod]
public void IncrementSubPhase_RollsBackToMoveChargersAfterEverythingElse()
{
MovementManager movementManager = new MovementManager();
movementManager.IncrementSubPhase(); // Go to compulsory moves
movementManager.IncrementSubPhase(); // Go to everything else
movementManager.IncrementSubPhase(); // Go back to Move Chargers
Assert.AreEqual(MovementSubPhase.MoveChargers, movementManager.CurrentSubPhase);
}
[TestMethod]
public void IncrementSubPhase_MovesForwardSubPhase()
{
MovementManager movementManager = new MovementManager();
MovementSubPhase firstPhase = movementManager.CurrentSubPhase;
movementManager.IncrementSubPhase();
MovementSubPhase secondPhase = movementManager.CurrentSubPhase;
Assert.AreNotEqual(firstPhase, secondPhase);
}
}

As expected, after resolving build errors (new class, property and method stubs) the two tests fail. And with the barest minimum of code:

public class MovementManager
{
public MovementSubPhase CurrentSubPhase { get; private set; }
public void IncrementSubPhase()
{
if (CurrentSubPhase == MovementSubPhase.EverythingElse)
{
CurrentSubPhase = MovementSubPhase.MoveChargers;
}
else
{
CurrentSubPhase++;
}
}
}

It all passes. Next up, there needs to be a way of preventing the Movement sub-phase from advancing when it is not the Movement phase at all. The expected behaviour for this should be a custom exception to be thrown, and dealt with elsewhere (presumably, the hypothetical UI). To fool it that it is not the Movement phase, it needs to have a reference to the GameManager – passed in as a constructor parameter to the MovementManager. The GameManager passed in for this test also needs to be mocked, so it will need to be given a public interface. One quick mocking later:

[TestMethod]
public void IncrementSubPhase_ThrowsExceptionIfNotMovementPhase()
{
bool correctExceptionThrown = false;
try
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
mockGameManager.Setup(item => item.CurrentPhase).Returns(TurnPhase.Shooting);
MovementManager movementManager = new MovementManager(mockGameManager.Object);
movementManager.IncrementSubPhase();
}
catch (WrongPhaseException ex)
{
correctExceptionThrown = true;
}
Assert.IsTrue(correctExceptionThrown);
}

Which is passed by:

private void ValidatePhase()
{
if (_gameManager.CurrentPhase != TurnPhase.Movement)
{
throw new WrongPhaseException("Cannot perform Movement actions in the " + _gameManager.CurrentPhase.ToString() + " phase.");
}
}

And calling that at the beginning of the IncrementSubPhase method.

Now it’s time to make some changes to the (as yet unused) Model class. Now it starts to get into things in a bit more of a distinct rule structure – the next line states that ‘models can move up to their move rate in inches in any direction’. I’m deciding that ‘inches’ refers to an arbitrary (and divisible) number, so a decimal will serve very well to decide how far they’ve moved, and how far they can move. The movement manager can either take in a co-ordinate to specify the target position, and change the model’s position to as far as it can go towards that point, or take in a distance and direction and move the model as specified.

It’ll probably be easier to sort out the distance and direction at the moment – those calculations will need to be made in the code that calls the MovementManager – though at some future point, these could be made into helper methods on the MovementManager. To work out where the model’s new position is, we need diagrams – this will have to wait until the next post!

This has been a nice long post that gets about halfway through page 10. I’m still not sure I’m allowing the design to emerge – I am, for example, thinking a few tests ahead of where I am – but at this stage, I’ve not (consciously) made a decision about design based on that forewarning, only on the basis of ‘I want Movement code separate from Game Manager code). This is more to do with the single responsibility principle than some master design drawn upfront.

This is a learning project I am documenting in order to teach myself TDD and unit testing – as I publish this, I have already written many parts in advance but I want to know what I’m doing wrong! If you see improvements or corrections, either to the code or the process, please leave a comment and let me know! Introduction to this project can be found here.

Leave a comment

Your email address will not be published. Required fields are marked *