Learning Unit Testing I – The Basics

Right, so I’ve chosen my project and I’m ready to begin. I’ll skip past the introduction, straight to page 8 of the rulebook. The characteristics section. This is basically a class layout, nothing too heavy, so I’ll start off by creating Model.cs:

class Model
{
public string Name { get; set; }
public int WeaponSkill { get; set; }
public int BallisticSkill { get; set; }
public int Strength { get; set; }
public int Toughness { get; set; }
public int Wounds { get; set; }
public int Initiative { get; set; }
public int Attacks { get; set; }
public int Leadership { get; set; }
}

Nothing really testable here yet. No point in testing basic getters and setters.

Next up is a description of the turn structure – this calls for a game manager of some sort. How about GameManager.cs, with an enum (TurnPhase)?

class GameManager
{
    TurnPhase CurrentPhase { get; private set; }
    int _numberOfPlayers;
    int _currentPlayersTurn;
}
enum TurnPhase
{
Movement,
Shooting,
CloseCombat,
Recovery
}

I think I’ll also add in an integer to GameManager to determine the number of players, and the number of the player whose turn it is. That should be enough to track that for now. To increment the turn onwards, though I’m not sure how that will be triggered yet, I need to add some actual logic! This should have a unit test. In proper TDD fashion, the test will be written first.

[TestMethod]
public void IncrementTurnPhase_RollsBackToMovementPhaseAfterRecovery()
{
GameManager manager = new GameManager();
manager.IncrementPhase(); // Go to Shooting
manager.IncrementPhase(); // Go to Close Combat
manager.IncrementPhase(); // Go to Recovery
manager.IncrementPhase(); // Go back to Movement
Assert.AreEqual(TurnPhase.Movement, manager.CurrentPhase);
}

This looks about right – but I’ll need to give GameManager a bit of a tidy up and make things a little more accessible. Now the code to pass that test:

public void IncrementPhase()
{
if (CurrentPhase == TurnPhase.Recovery)
{
CurrentPhase = TurnPhase.Movement;
}
else
{
CurrentPhase++;
}
}

That’s nice and neat. But I found that without writing any code in that method, it still passes – since the turn phase is still Movement. Another test to make sure that it only increments one space will probably be in order.

[TestMethod]
public void IncrementTurnPhase_MovesForwardPhase()
{
GameManager manager = new GameManager();
TurnPhase firstPhase = manager.CurrentPhase;
manager.IncrementPhase(); // Go to Shooting
TurnPhase secondPhase = manager.CurrentPhase;
Assert.AreNotEqual(firstPhase, secondPhase);
}

This one does the trick. Makes sure that the phase has changed within the turn.

Finally, the last couple of paragraphs on page 9 say that control alternates between players. I know from experience that there could easily be multiple players, and I want to be ready for that. So the GameManager will increment _currentPlayersTurn every time the turn finishes (after the Recovery phase), and reset the _currentPlayersTurn integer back to 1 when it exceeds _numberOfPlayers.

Once more, write a test to check that it increments at the end of a turn:

[TestMethod]
public void IncrementTurnPhase_ChangesPlayerAtEndOfTurn()
{
GameManager manager = new GameManager();
int firstTurn = manager.CurrentPlayersTurn;
manager.IncrementPhase(); // Go to Shooting
manager.IncrementPhase(); // Go to Close Combat
manager.IncrementPhase(); // Go to Recovery
manager.IncrementPhase(); // Go back to Movement
int secondTurn = manager.CurrentPlayersTurn;
Assert.AreNotEqual(firstTurn, secondTurn);
}

Now to test the next bit, it’ll be necessary to add a proper constructor with a parameter – number of players. Here’s the test:

[TestMethod]
public void IncrementTurnPhase_ReturnsToFirstPlayerAfterAllHaveHadTurn()
{
GameManager manager = new GameManager(2);
manager.IncrementPhase(); // Go to Shooting
manager.IncrementPhase(); // Go to Close Combat
manager.IncrementPhase(); // Go to Recovery
manager.IncrementPhase(); // Go back to Movement
manager.IncrementPhase(); // Go to Shooting
manager.IncrementPhase(); // Go to Close Combat
manager.IncrementPhase(); // Go to Recovery
manager.IncrementPhase(); // Go back to Movement
Assert.AreEqual(1, manager.CurrentPlayersTurn);
}

And the code that passes both of those tests:

public GameManager(int numberOfPlayers)
{
NumberOfPlayers = numberOfPlayers;
CurrentPlayersTurn = 1;
}
public void IncrementPhase()
{
if (CurrentPhase == TurnPhase.Recovery)
{
CurrentPhase = TurnPhase.Movement;
if (CurrentPlayersTurn == NumberOfPlayers)
{
CurrentPlayersTurn = 1;
}
else
{
CurrentPlayersTurn++;
}
}
else
{
CurrentPhase++;
}
}

After adding the requirement for a number of players to the other tests, all the tests so far pass. There is, as I’ve been warned, more test code than real code (67 lines in GameManagerTests compared to 40 in GameManager) but seeing all those little green ticks is definitely a psychological boost. As I’ve neatly finished page 9 and the ‘Rules’ section, I will start the ‘Movement’ section next time. This will have a bit more design than the fairly sparse classes here, and a bit more deliberation over where to put particular bits of code. I know a big idea of TDD is to write, then refactor, but I don’t want to do too much refactoring. It could become quite a hassle, especially later in the day. We’ll see when we get there!

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.

My Next Learning Project

I’ve long ago established that I learn best from doing things. Even if those ‘things’ never get anywhere, the journey through real problems helps me get a handle on what they are. My army list program got me through WPF, and then MVC. It’s faltered, since I don’t really have the enthusiasm for it that I once did (I’ve spent over a year on it, and as it is a learning project I keep needing to redesign things…)

This brings me to my new idea. Everyone who is anyone in .NET programming at the moment is unit testing. I’ve read a lot about unit testing, and dependency injection, and all those things but I am not entirely convinced I am doing it right. It was when I tried to apply these things to the wargame tools / army list program that I realised I had lost my direction with that one, and it was time to move to something new. Sticking with what I knew best, I initially thought about a WFRP (second edition, naturally) calculator or helper of some sort – then quickly abandoned that idea as madness.

But what about an easier system? Necromunda is a relatively simple game system. Something to calculate the effects of it’s combat, shooting modifiers, exotic weapons and the many charts and tables for the end-game clean-up would be ideal. If I felt adventurous, I could even add in Gorkamorka variants.

The scope I am envisioning is a disconnected class library, capable of managing and running a game of Necromunda. In theory, I could hook it up to a Silverlight, WPF or XNA (ha!) frontend, and all the functionality will be there to go. I would just need to connect certain bits for display. As it is all pure logic, it should be a good way to practice unit testing using a Test-Driven Development approach.

I’ll be documenting each step of the way in here, so I am forced to think about and describe what I’m doing. The rules for the game are available for free (click on the image to get them) from Games Workshop, so it shouldn’t be a problem me mentioning the odd one or two, followed by reams of code.