Greetings and welcome to the fourth installment where you, gentle blog reader and better practices enthusiast, have the opportunity to pair-program with me as I tackle some old and hoary code I wrote four years ago in an attempt to buff it into respectability. While the app in question is a .NET Windows Forms component that implements a chess board, this series is focusing on the rules engine behind it.
Today, I’ll be demonstrating how I crafted unit tests to exercise the rules engine with replays of classic (and not so classic) chess games – specifically, I want to ensure that I have a baseline of tests that demonstrate legal moves, captures, checks and mates.
Housekeeping
In my last post, I mentioned that the goal for this article would be to have the source code available for download via an online repository – as of Monday, I set up a Google Code Subversion repository for this purpose and will be using it going forward so that you can follow along with the revisions to the code as they’re made. I also mentioned that we’d be getting into some beefier tests – while this is the case, it’s not as beefy as I’d have liked as I ran into some unexpected difficulties. More on that later.
Unit Test Goal: Replaying Classic Chess Games
I the last installment, I wanted to craft some unit tests that I could use to replay classic chess games from history like Capablanka v. Alekhine 1927 or Stahlberg v. Petrov 1938 – the purpose was manifold:
- These games are usually 25+ moves in length, and because of the skill of the players involved, incorporate a wide array of moves and techniques;
- Because the games are historic, I know that each move is legal and the outcome for each move;
- Pushing the moves into the engine would validate the baseline behaviour for the MakeMove() method;
- Most importantly, the returned PlayerMoveResult struct type provides metadata to validate the outcomes for each half move (per side) telling us a great deal about how the internals of the engine are functioning.
With this objective in mind, I set about thinking of how to capture or generate test data for classic games that I could easily consume inside a unit test. My first instincts were to set up a delimited file with the algebraic coordinates for each move, along with validation flags for the move type and outcome – ooh! Maybe use XML, have some XPath queries to fetch the half moves and outcomes…
Stop. Stop it right there! As cool as this would be, it was also introducing complexity where I didn’t need it since I’d now have to be accountable for ensuring that the code to process the XML was tested and valid. Instead, I decided to do the simplest thing that works and began roughing-in a simple string array with delimited fields that would identify each half move along with corresponding expected outcomes for move type and result:
34 class TestGames
35 {
36 // Capablanca vs. Mieses 1913
37 public static string[] Capablanca_Mate_Mieses_1913 = new string[]
38 {
39 "D2-D4//nc/G8-F6//nc",
40 "G1-F3//nc/C7-C5//nc",
41 "D4-D5//nc/D7-D6//nc",
42 "C2-C4//nc/G7-G6//nc",
43 "B1-C3//nc/F8-G7//nc",
44 "E2-E4//nc/E8-G8//O-O",
45 "F1-E2//nc/E7-E6//nc",
46 "E1-G1//O-O/E6-D5//x",
47 "E4-D5//x/F6-E8//nc",
48 "F1-E1//nc/C8-G4//nc",
49 "F3-G5//nc/G7-C3//x",
My intent here is to have a simple string delimited with forward-slashes “/” to indicate each half move, result and type starting with white:
12 /// The strings for each move are structured in the following manner:
13 /// "{white from}-{white to}/{white result}/{white move type}/
14 /// {black from}-{black to}/{black result}/{black move type}"
Next, I wanted to validate the result for each move and indicate if the move resulted in material capture, castling, en passant capturing, pawn promotion, etc. I decided to borrow the codes and symbols for move results and types that are used in Standard Algebraic Notation for games to keep things intuitive and simple:
19 /// {result} has the following expected values:
20 /// "": Legal move, no immediate consequence
21 /// "!": Illegal move
22 /// "+": Move has placed opponent in check
23 /// "++": Move has placed opponent in check mate
24 ///
25 /// {move type} has the following expected values:
26 /// "x": Capture
27 /// "nc": Non-capturing move
28 /// "O-O": King-side castle
29 /// "O-O-O": Queen-side castle
30 /// "xep": En-passant capture
31 /// "!": Illegal move
32 /// "^": Pawn promotion
So far, so good. However, I soon began to realize a new problem with the arrays – they’re laborious to construct and prone to errors when entered by hand, especially because I was transcribing the moves from a book that used the old-style notation. I solved this problem by creating a quick WinForms app that used the existing chessboard control to capture moves and transcribe them into a format I could easily cut & paste into my array definitions:

This might seem like cheating: After all, if my purpose of tests is to validate the engine’s behaviour, how can I be certain that what I’m capturing here is valid to use as input? Simply put, I’m using my own knowledge to verify that the moves and results correspond to the outcomes for the game, ie. captures, checks and mates – in other words, I’m following the first principle in Hunt & Thomas’ maxim about unit tests: Are the results right?
For the curious, I’ve added the above app to the solution under the RNChessBoardControl.DemoApp project which you’ll notice when you pull down the latest revision 11 or later of the code. I won’t delve into this for now so as to keep things brief, but you can easily see by viewing the code that it’s quite lightweight and didn’t take too much effort to build out. In this situation, crafting a quick tool that will save time later on is worth the time investment, especially to get test input data that we can be confident about.
Writing the Playback Tests
Using the tool, I captured three games into static string arrays that placed into a separate class, TestGames, which I kept in the same namespace as my test fixture for easy reference. At a high level, my plan for the playback test was simple:
- Iterate over the array for a sample game;
- Split each move string into constituent parts for the moves and results for each side;
- Push each move into the engine;
- Use Assertions to validate the move result and type.
My first cut at this method had everything happening in a single method so I could capture the essence of what I wanted to do:
Rev 6: makemove_fullgametomate_legal()
Definitely not pretty, however I wanted to capture the logic and validate the behaviours. There was definitely a little trial and error that I had to overcome with respect to parsing the moves, which I eventually consigned to some Regex pattern matching. Also note the GetMoveResultStringAsSAN() and GetMoveTypeStringAsSAN() methods which convert the PlayerMoveResult and MoveType enumerations returned for each move into strings that correspond to the SAN codes I’m using in the arrays:
Rev 6: GetSAN_helper_methods
While this test ran and corroborated the results, it needed to be refactored because it wasn’t very well focused – in other words it was exhibiting some code smells.
Step 1: Apply the Extract Method Refactoring
In order to address my smelly code, it seemed a good idea to split the array iteration/move entry code from the test method. Easy-peasy: Using the Refactor! Pro Visual Studio add-in, all I needed to do was highlight the code within the method definition and then click the elipses (…) that appeared below to trigger the Extract Method refactoring:

Clicking Extract Method, I’m prompted to specify where I want the new method to go and what it would be called:

I decided to move the new method below the test method stub, so I hit the down key and then enter – presto, our method has been riven in twain:

In order to make this change more meaningful, I decided to rename the method and add an argument for passing in a string array for the test game:

I then rebuilt the tests and ran them to verify everything was in working order before committing the changes to the repository under revision 8, and then added additional test methods for the other two games in revisions 9 and 10.
Step 2: DRY Refactorings
In the Pragmatic Programmer text, Hunt and Thomas introduce a concept that serves as the root for many refactorings called the DRY Principle or “Don’t Repeat Yourself”. This means we should avoid duplicating code wherever possible and collapse those segments we find into separate methods. If we look in the PlayTestGame method, there’s definitely some duplication happening:

The code segment above is practically identical to the block for validating the black test game move – the only differences are the string elements from the moveParts array that identify the moves and expected results and type. Refactor! Pro suggested that I extract this block into a new method with two arguments: moveIndex and moveParts[]:

Close, but no banana. The suggested method, GetPmr(), while a step in the right direction is locked to the ordinal positions for white’s move from the split array (ie, indices 0,1,2) – I’d end up creating a duplicate method for black’s move! It's also rather poorly named for my purposes. I decided to let the tool stub-out the method for me, but renamed it and changed the signature slightly:

I applied some renaming refactorings to make the intent of the method more generic for its new purpose:

All I had to do now was revise the calling method arguments, build and test. Note that at this point, I did not apply the refactoring the black move methods below – I wanted to confirm that the refactored code I had introduced was in fact working:


Awesome – all that was needed now was to replace the duplicate code for black with a similar method call to ExecuteTestGameMove() and pass in the elements from moveParts[]:

As we can see, even here in our test fixture we’ve gained some advantages for refactoring our code – our tests will be easy to read and maintain and we’ve consolidated four Asserts into two within an isolated method.
Rounding out this session, I finished up with additional test methods to run the two other sample games I added to the TestGames class.
Next Steps…
For the next installment in this series, I’ll add some additional test methods and finally get back to tackling the refactorings I’ve wanted to introduce to the DoMove() method. Check the code repository for updates to the codebase as I won’t be writing about them all as we go forward – in fact, there are additional tests for some edge cases that I’ll be adding over the next day or so. Cheers!