Tuesday, October 6, 2009

I Love Tests

I don't think you usually hear a college student say that. I love tests. But ask any software developer and they'll probably give you the same response. Well-written tests not only makes sure that your code is working well, but that it'll be working well in the future. And there's Test Driven Development (TDD), where we write a failing test first and then write the code needed to pass the test. I had the opportunity to hear Kent Beck (co-creator of JUnit) speak about TDD and JUnit. He mentioned that TDD seemed like such a silly idea; that you write code that doesn't work and then have to write more code just to fix it. Yet they used TDD when creating JUnit and found that they were more productive. If you're not a believer, maybe you need to take Software Engineering at UH Manoa.

I always liked tests, but relearning about them in ICS 613 reignited my passion. So much so that I wrote a few unit tests for my iPhone application (Apple calls them "logic tests") and did some TDD to add a new feature. So I dove into writing a few tests for my Robocode project. I had ideas on what tests I could run, but as I said in my previous blog, things rarely go as planned.

I had the idea that I would create unit tests that test the event handlers for my Menehune robot (OnScannedRobot and OnHitByBullet). I'd just create a bogus event and test that certain properties of Menehune were set. The difficulty was that if we instantiate our Menehune robot, we need to run the run method to access certain properties of the robot. Unfortunately, the run method is typically an infinite loop. In the OnHitByBullet test, I could get by without having any exceptions thrown. As for OnScannedRobot, I did a check that the exception is thrown (the test fails if it isn't thrown) and then check for some internal properties. To do that I had to move my code around so that movement and firing decisions came later.
  public void testOnScannedRobot() {
    
// Initialize an event with bogus values.
    
ScannedRobotEvent event = new ScannedRobotEvent("Foo", 100, 0, 10, 0, 0);
    
try {
      robot.onScannedRobot
(event);
      
fail("Should have thrown exception where we attempted to move or fire.");
    
}
    
catch (RobotException e) {
      assertEquals
("Testing scanned robot name.", event.getName(), robot.getScannedRobotName());
      
assertEquals("Testing robot mode.", Menehune.RobotMode.FIRE_MODE, robot.getMode());
    
}
  }



Example where I fail if an exception is not thrown.

Next, I needed to test my robot's behavior. We were provided with Philip Johnson's RobotTestBed code that provided a test box for our robots. We could check the conditions of the robots after each turn, round, or battle. I had the idea where I'd access methods in my Menehune robot to make sure that it was behaving properly. Yet I was foiled again! We can't actually access instances of our robot. We just have a generic overview (snapshots in their case) of where the robots are at a given time. Thus, to determine if my robot was behaving properly, I tracked its movement when it encountered an enemy. That way I could check that the robot tracked down an enemy and then repositioned itself.

Tests against other enemies went fairly smoothly though. I gave myself a fairly conservative win percentage against RamFire, but I just wanted to make sure that I win most of the time.

I then ran a code coverage tool (Emma) to see how well my tests cover my robot. Overall it was pretty good. I used an enum type to represent the different modes of my robot. Emma got me for not testing all of the methods for an enumerated type, which I think is kind of bogus. My robot also apparently didn't turn in certain directions, so those lines were missed. Finally, I only tested my robot against one enemy, so the line that skips the enemy if we're not tracking it is not covered. Further tests might cover some of these aspects, but I'd say it's pretty good coverage otherwise.

So what if I never called RobotMode.valueOf()?

Overall, I can say that my love for tests are back. If we spend more time developing and improving our robots, I might be inclined to write a few more. I love tests. Exams, not so much.

You can download my robot here.

No comments:

Post a Comment