The Next Home of Chris Chapman's Free Thoughts on Agile, .NET, SharePoint, what-have-you, whatnot. 
# Thursday, November 15, 2007

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:

Quick_board_app

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:

  1. Iterate over the array for a sample game;
  2. Split each move string into constituent parts for the moves and results for each side;
  3. Push each move into the engine;
  4. 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:

Extract_method_makemove_fullgametomate

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

Extract_method_makemove_fullgametomate_2

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:

Extract_method_makemove_fullgametomate_3

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:

Extract_method_makemove_fullgametomate_4

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:

Dry_playtestgame_white

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[]:

Dry_playtestgame_white_suggestion

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:

Dry_playtestgame_white_1

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

Dry_playtestgame_white_seg2

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:

Dry_playtestgame_white_seg3
Dry_playtestgame_white_success

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[]:

Dry_playtestgame_black_refactor

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!

Thursday, November 15, 2007 5:54:24 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
refactoring | rnchessboardcontrol | tdd | unit testing

# Wednesday, November 14, 2007
Update:  'Seems I'm not the only one who's excited about the TDD potential that ASP.NET MVC opens up.  Phil Haack is already all over this one with his post Writing Testable Code Is About Managing Complexity.

I’m trying to curb my enthusiasm here, but I’m excited after reading this first part of ScottGu’s in-depth coverage on his team’s upcoming ASP.NET MVC Framework that we can expect to see in VS2008.

What’s got me really keyed-up is the potential that the MVC model will give us for unit testing web applications.  I could care two figs about the latest syntactic sugar that the product teams think we all want – they’re useless if I can’t do TDD (test-driven-development) and CI (continuous integration) against them.  And ASP.NET web apps have been public enemy #1 for most attempts to unit test – witness: SharePoint.

Here’s how Scott sees TDD happening under MVC (emphasis mine):

…part of what makes an MVC approach attractive is that we can unit test the Controller and Model logic of applications completely independently of the View/Html generation logic.  As you'll see below we can even unit test these before we create our Views.

The ASP.NET MVC framework has been designed specifically to enable easy unit testing.  All core APIs and contracts within the framework are interfaces, and extensibility points are provided to enable easy injection and customization of objects (including the ability to use IOC containers like Windsor, StructureMap, Spring.NET, and ObjectBuilder).  Developers will be able to use built-in mock classes, or use any .NET type-mocking framework to simulate their own test versions of MVC related objects.

Mvc_testproject

Pct_test

The striking thing I see out of all of this is that Scott is envisioning an entirely new way of advancing the development paradigm:

  1. ASP.NET MVC incorporates a best practice design pattern that’s long been known outside of our camp and one we’ve really wanted;
  2. It’s taking some positive cues from our Ruby on Rails bretheren (eg. Models, Views and Controllers folders, ease of testing);
  3. It is an alternative to, not a replacement for standard ASP.NET webforms – you can quite happily live in a coding cave if you wish;
  4. You may use integrated MSFT technologies for testing and dependency injection, or use what you like, eg. NUnit, xUnit, Windsor, etc.

I like this.  I like this a lot.  I’m also hoping to hell that the higher-ups don’t foul this up for the rest of us – ScottGu’s on the right wavelength here and I’m really impressed he’s advancing so far with this.

Wednesday, November 14, 2007 9:01:01 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
.net | asp.net | better practices | design patterns | unit testing

# Tuesday, November 13, 2007

It’s that time of year again, kids!  Another .NET namespaces and types poster has been cranked out of Redmond:

Dotnet_35_poster_ds

While these are pretty from an esthetic perspective (look at the soft pastel colors and swooshes!), they really are quite useless.  Sure, you can glean how the Framework has changed to incorporate new functional groups, but are you really going to consult this chart when working on your next 3.5 project?

No, it’s more likely we’ll all be hitting CTRL-ALT-J or load up Reflector or Google the damn object.  Oops, I mean “Live Search” the damn object.

Satisify your urge to get yet another poster and download it here.

Tuesday, November 13, 2007 8:47:45 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
.net

# Monday, November 12, 2007

Recently, I’ve noticed some furtive spamdexing attempts in the comments to several of my older posts – in spite of having enabled dasBlog’s built-in CAPTCHA validation component.  I knew from previous experience that these were “scout” entries designed to test my defenses before an all-out onslought.  Unfortunately for the spammers, I had also configured by blog to disable link posting and cut off comments for posts older than 60 days.  This limited their attack surface, but I knew that  I needed to do something to confound these guys before my blog became another broken-window site on the interwebs advertising Viagra and pr0n sites.

Enter: reCAPTCHA

Over the summer I had read about a new advancement in blog spam protection by the folks from Carnegie Mellon who brought us the original CAPTCHA concept called reCAPTCHA, which not only stymies spambots but helps in the archiving of human knowledge from books in the process.  It does this by presenting would-be comment posters with two words to interpret from distorted images:  One is an auto-generated word which the system can validate, the other is a failing OCR capture from a book that is being digitized – but the end user (and spambot) doesn’t know which is which:

ReCAPTCHA_sample

I thought this was pretty cool – it’s like a low-tech version of Stanford’s FoldingAtHome project where the web’s multiplier effect is put toward digitizing books instead of unravelling protein folding sequences.  Instead of having users just enter some mindless string, their ten-second investment to validate their post could be put to some good use while making it more difficult for bots to corrupt my comment entries.  Time to try it out! 

Adding reCAPTCHA – The high level overview

reCAPTCHA can be added to just about any type of site – there are plenty of instructions available on the main site.  For our purposes, we need to do several things:

  1. Create an account for our domain via the site – this will provide us with two vital parts for installing reCAPTCHA:  A generated public/private key pair;
  2. Download the ASP.NET library and copy into the bin folder for our web application;
  3. Modify the site.config to hide the old-n-busted CAPTCHA component;
  4. Modify the CommentViewBox.ascx file to implement the reCAPTCHA control and register it with our account;
  5. Test!

1.  Create a reCAPTCHA account

  • Pretty straight-forward – go here click "Sign up now!" and fill in the fields, set up a password and copy your public and private key strings to notepad.

2.  Download and install the reCAPTCHA Assembly

  • Get it by clicking the link on this page.  You’ll get an archive folder that you can decompress on your system.  Go inside the release folder, find the Recaptcha.dll assembly and FTP or copy into your dasBlog installation’s Bin folder.

3.  Disable dasBlog’s old CAPTCHA component

  • You may want to quiesce your live box before doing this by disabling all comments in the site configuration before proceeding.
  • Locate the <enablecaptcha> element in the site.config file located in your dasBlog installation’s SiteConfig folder and set its value to false:
    Dasblog_enable_captcha2

4.  Add reCAPTCHA component to the CommentViewBox.ascx control file

  • Add a control registration directive to the top of the page:
    Dasblog_recaptcha_1
  • Add the reCAPTCHA control declaration below the old CAPTCHA control and sub-in the public and private key codes that you obtained during registration:
    Dasblog_recaptcha_2

5. Test!

  • Navigate to one of your posts from the main page;  your comments section should look similar to the following:
    Dasblog_recaptcha_3
  • Note that the control has automagically hooked up to the ValidationSummary control that’s in the CommentViewBox control definition – by default it should read “The verification words are incorrect.”
  • Test by entering a valid name and comment, then the pair of words.  On postback, the CommentViewBox control verifies that the page is valid according to the results returned from the Recaptcha control.

 

Monday, November 12, 2007 5:18:04 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
asp.net | blog

Google_code_rnchessboardcontrol2A quick post for this morning – I’m still working on the material for the next post in the “Refactoring” series, but I did want to advise that I’ve created a Google Code project where I have posted the source code to a SVN (Subversion) repository that I’ll be using for the duration of the project.  This will allow those of you following along at home to pull down copies of the code by revision number – ie. you can “get latest” or anything up to that point.

Accessing the Source

The Google Code site can be found here:

http://code.google.com/p/rnchessboardcontrol/

The SVN repository can be found here:

http://rnchessboardcontrol.googlecode.com/svn/trunk

You will need a Subversion client to pull the code down to your local machine.  There are several flavours of Subversion that are available, as well as client apps – personally, I use the following:

CollabNet’s Open Source Subversion Server and Client

Download the Server and Client for Windows from here:

Collabnet_svn_windows

Tortoise SVN Windows Explorer Extension

SVN is primarily a command-line tool, which if you get proficient with it is fairly quick.  But I’m generally happy with the advances the GUI has afforded us.  So I use Tortoise SVN to provide me an easy way to work with Subversion right from the Windows Explorer.

Download the Tortoise here:

Download_tortoise

Bringing up the RepoBrowser

The TortoiseSVN Repo-browser allows you to navigate remote or local Subversion repositories through a simple modeless window.  You can bring it up by right-clicking in any open folder space and navigating the context menu thus: 

Tortoise_nav_repobrowser

This will bring up the Repo-browser window where you can now enter the URL for the remote repository:

Tortoise_repobrowser_remoternc

Once the connection to the remote repository is established, expand the “trunk” folder to see the source elements:

Tortoise_repobrowser_trunk

Downloading the Source

Right-click the trunk folder in the Repo-browser and select “Check Out” – this will bring up the following dialog where you can specify the location where you want to locate your working copy:

Tortoise_repobrowser_checkout

If the folder doesn’t exist, TortoiseSVN will create it for you – click OK and you’ll begin pulling the source.  Here’s what a successful checkout should look like:

Tortoise_repobrowser_download

Navigate to your working copy folder and you’ll see the latest revision of the code, which is currently at 2.  This number will increase as we roll along, but you can opt to revert to any version you wish quite easily so you can view diffs and quickly see changes as they happened.

Rnchessboardcontrol_workingcopy

Have fun!

 

Monday, November 12, 2007 8:59:18 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
better practices | refactoring | rnchessboardcontrol | subversion

About Me
I am a Toronto-based software consultant specializing in SharePoint, .NET technologies and agile/iterative/lean software project management practices. Currently, I am employed by Microsoft Consulting Services (MCS) Canada as an Application Development and Information Worker Consultant, focusing on delivering guidance and subject matter expertise to enterprise customers who have or are in the process of deploying Microsoft technologies.

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010
Chris R. Chapman
Sign In
Archive
<November 2007>
SunMonTueWedThuFriSat
28293031123
45678910
11121314151617
18192021222324
2526272829301
2345678
Statistics
Total Posts: 194
This Year: 2
This Month: 0
This Week: 0
Comments: 109
All Content © 2010, Chris R. Chapman
DasBlog theme 'Business' created by Christoph De Baene (delarou)