writing the first acceptance test for robocode

In previous posts I've set up an acceptance testing framework that enables me to run a battle and I'm now ready to write my first acceptance test.

To recap, my acceptance test that I want is:

In a one round battle, fighting against a single robot that does not move, the slayer robot should win.

So here's how I want to write that:

    public class in_a_one_round_battle_fighting_against_a_single_robot_that_does_not_move
    {
        Establish context = () =>
        {
            battle = new Battle("in_a_one_round_battle_fighting_against_
a_single_robot_that_does_not_move"
); battleRunner = new BattleRunner(new ProcessRunner(),
new BattleResultParser(new BattleResultsFileReader())); }; Because of = () => returnedResults = battleRunner.Run(battle); It should_result_in_the_slayer_robot_winning = () => returnedResults.Where(r => r.RobotName.Contains("SlayerRobot")) .Single() .Position.ShouldEqual(1); static Battle battle; static BattleRunner battleRunner; static IEnumerable<BattleResult> returnedResults; }

Now, I manually create a battle file in the battle directory with the same name and set up the battle:

oneroundbattle

I'm ready to go with the first acceptance test and when I run it, the battle runner runs the process, the results are parsed and the test fails with the following:

firstacceptancefails

My acceptance test fails because my robot is in second place - the acceptance testing framework works!

I now recognise some areas that I can abstract some of the set up so here's the first process of streamlining as I write a base acceptance specification:

    public class acceptance_test
    {
        Establish context = () => battleRunner = new BattleRunner(new ProcessRunner(), 
                                       new BattleResultParser(new BattleResultsFileReader()));

        Because of = () =>
                         {
                             battleName.ShouldNotEqual(string.Empty);  //battleName must be set 
                             battle = new Battle(battleName);
                             returnedResults = battleRunner.Run(battle);
                         };

        protected static string battleName = string.Empty;
        protected static IEnumerable<BattleResult> returnedResults;
        static Battle battle;
        static BattleRunner battleRunner;
    }

This base acceptance class now enables me to have a very small amount of code to write for an acceptance test:

    public class in_a_one_round_battle_fighting_against_a_single_robot_that_does_not_move : 
acceptance_test { Establish context = () => battleName =
"in_a_one_round_battle_fighting_against_a_single_robot_that_does_not_move"; It should_result_in_the_slayer_robot_winning = () => returnedResults.Where(r => r.RobotName.Contains("SlayerRobot")) .Single() .Position.ShouldEqual(1); }

I can make this even shorter now by adding in an extension method:

    public static class BattleResultCollectionExtensions
    {
      public static BattleResult SlayerRobotResult(this IEnumerable<BattleResult> battleResults)
      {
          return battleResults.Where(r => r.RobotName.Contains("SlayerRobot")).Single();
      }
    }

Now my acceptance test looks great:

    public class in_a_one_round_battle_fighting_against_a_single_robot_that_does_not_move : 
acceptance_test { Establish context = () => battleName =
"in_a_one_round_battle_fighting_against_a_single_robot_that_does_not_move"; It should_result_in_the_slayer_robot_winning = () => returnedResults.SlayerRobotResult().Position.ShouldEqual(1); }

I could go further and make the SlayerRobotResult part of the base acceptance, but I'll leave this for now as I'm happy with how the test looks.

I now have a quick acceptance testing framework where I can ensure that I do not regress the overall outcome of certain battle situations and this series of posts illustrated how you can think out of the box a little and make white box acceptance testing possible up front before you develop the main parts of your application.

At a future date we may want to look at doing this in-process as opposed to launching an external process - Pavel and Jason have comments about using a jni4net bridge to perhaps accomplish this and it would be great if an acceptance testing mechanism could be included as part of the robocode distribution.



1 comments:

  1. Jason Hyland July 27, 2010 at 5:13 PM

    Hi Justin,

    Excellent stuff so far! I've got the jni4net robocodeengine itch now, and I just can't get past it :)

    Having said that, there is elegance in the approach you've taken, and it does mean that you've developed a framework for acceptance testing already!

    I'll keep you posted!

    Regards, Jason

    PS, Who won the first battle?