Robocode: Unit Testing Goodness

Unit testing a very important part of a software life cycle. Assuming that the development meets all of its requirements, testing ensures that the software will function properly. Every since the previous software engineering classes, JUnit has become an integrate part of my development of any Java based software. I hope that I can continue this with the testing my robot, Hunter.

Experience with RobotTestBed Testing
Testing my robot is a lot like testing Java Servlets, since we are testing integration. Because the amount of variation between each battle scenario, there does not exist a method to control the battle parameters. Thus, our tests boil down to: will the robot fire correctly, is the fire power level correct, or does robot A beat robot B 80% of the time?

Due to integration testing, I created a separate helper class to abstract the mathematical methods way from my robot. In this way, I can run some unit tests over the various methods to determine whether my math is correct (or not). In hindsight, I still need to implement a method to ensure that my robot does not get stuck on a wall.

package bki;

import static org.junit.Assert.assertTrue;
import robocode.Rules;
import robocode.control.events.TurnEndedEvent;
import robocode.control.snapshot.IBulletSnapshot;
import robocode.control.snapshot.IRobotSnapshot;
import robocode.control.snapshot.ITurnSnapshot;
import robocode.control.testing.RobotTestBed;

/**
 * Tests the {@link Hunter} robot.
 * 
 * @author Bret K. Ikehara
 */
public class TestHunter extends RobotTestBed {

  private static final String myRobotName = "bki.Hunter*";

  /**
   * Specifies the robots that will fight.
   * 
   * @return The comma-delimited list of robots in this match.
   */
  @Override
  public String getRobotNames() {
    return "sample.Tracker,bki.Hunter";
  }

  /**
   * This test runs for 20 rounds.
   * 
   * @return The number of rounds.
   */
  @Override
  public int getNumRounds() {
    return 20;
  }

  /**
   * Tests that a bullet is fire every turn.
   * 
   * @param event {@link TurnEndedEvent}
   */
  @Override
  public void onTurnEnded(TurnEndedEvent event) {
    ITurnSnapshot turn = event.getTurnSnapshot();
    IRobotSnapshot[] robots = turn.getRobots();

    // tests the firepower.
    for (IBulletSnapshot bullet : turn.getBullets()) {
      IRobotSnapshot robot = robots[bullet.getOwnerIndex()];
      if (myRobotName.equals(robot.getName())) {
        // fire power is limited when life is low.
        if (robot.getEnergy() > 10.0) {
          boolean test = testDouble(Rules.MAX_BULLET_POWER, bullet.getPower(), 0.3);
          assertTrue("Always max fire power: " + bullet.getPower(), test);
        }
      }
    }

    // TODO ensure robot doesn't get stuck on wall.
  }

  /**
   * Checks whether a double is equals with offset.
   * 
   * @param expected double
   * @param value double
   * @param epsilon double
   * @return boolean
   */
  public boolean testDouble(double expected, double value, double epsilon) {
    return (expected - epsilon < value) && (expected + epsilon > value);
  }
}

Code Coverage with Jacoco
After finishing up my tests, I ran the Jacoco tool to ensure that the major portion of my code has test coverage. As we had discussed in class, 100% test coverage does not imply that the code is well tested or meets predetermined requirements. I received an 85% coverage which was expected as I had not completed the RobotHelper.calculateAngleToHeading method for predictive firing. If we ignore that certain test, then the rest of the code is covered well.

jacoco

After Thoughts
After my experience with JUnit and Jacococ, I realize that I really need to mature my testing skills. Although the unit testing portion came naturally, the RobotTestBed gave me a some trouble trying to find valid tests for my robot. Definitely, I need to become more familiar with the RobotTestBed class.

Advertisements