Code Kata – Bowling Game

Bueno en el último post dije que iba a probar TDD, y ésto es el resultado del primer experimento. Leyendo el blog de Carlos Buenosvinos (lo recomiendo, esta lleno de cosas interesantes) encontré su post sobre el Kata “Bowling Game”.

Ya lo he hecho: https://github.com/danksearle/kata_bowlinggame.

2015-03-17_20-47-34

Ejemplos de los tests:

 public function testGivenGameExample()
 {
     $game = new Game;
     try {
         $this->processFrames($game, array(
             array(1, 4), // 5
             array(4, 5), // 14
             array(6, 4), // 29
             array(5, 5), // 49
             array(10), // 60
             array(0, 1), // 61
             array(7, 3), // 77
             array(6, 4), // 97
             array(10), // 117
             array(2, 8, 6), // 133
        ));
     }
     catch (Exception $e) {
         $this->fail('An unexpected exception has been raised. ' . $e->getMessage());
     }
     $this->assertEquals(133, $game->score()); // Test with rolls from the given example.

     return;
 }
 public function testPerfectGame()
 {
     $game = new Game;
     try {
         $this->processFrames($game, array(
             array(10),
             array(10),
             array(10),
             array(10),
             array(10),
             array(10),
             array(10),
             array(10),
             array(10),
             array(10, 10, 10),
          ));
     }
     catch (Exception $e) {
         $this->fail('An unexpected exception has been raised. ' . $e->getMessage());
     }
     $this->assertEquals(300, $game->score());

     return;
 }

Tardé un poco más que los 40 minutos de Carlos … un poco bastante. Bueno, hay que empezar de alguna forma. :-) Veo dos maneras de juzgar mis resultados. Primero “¿he hecho bien el Kata?” y segundo “¿he utilizado bien el TDD?”. Creo que me he pasado de largo los requisitos del Kata, o mal interpretarlos porque para entender las normas he recurrido a wikipedia … y creo que debería limitarme a lo que dice el kata y no buscar más allá. Pero era difícil entender cómo calcular los puntos en el último frame. Pero en la segunda cuestión creo que el TDD me ha ido bastante bien, no se si he escrito más tests de lo necesario, pero opino que menos tests no sería muy riguroso. Y al final tengo confianza en que calcularía bien cualquier partido.

Me esforcé a hacerlo siguiendo el principal de TDD de empezar con los tests, y luego el código.

Al principio era difícil de imaginar los tests. Empece con los fáciles, los tests de valid inputs, cómo string en vez de integer. Luego para probar con un partido entero añadí este method para facilitarlo:

 /**
 * Process an array of frames, each frame is an array of rolls.
 * @param Game $game 
 * @param array $frames
 */
 private function processFrames($game, $frames) {
     foreach($frames as $frame) {
         foreach($frame as $roll) {
             $game->roll($roll);
         }
     }
 }

Con éste función podría escribir los tests como en los ejemplos arriba, así son más legibles.

Entonces empece con los códigos, intentando solucionar los tests de uno en uno. A veces grupos de tests se solucionan con un solo cambio. Los últimos tests de caer eran los del method score(). Refactoré varios veces – la lógica me resultaba difícil de organizar. No se si era un requisito o no para validar los rolls en acuerdo con las reglas del juego, pero yo quiría hacerlo así. Entonces tenía código para validar, y luego código para calcular. Para validar mira atrás para ver en que estado esta el partido, pero para calcular el score por cada roll, si es strike o spare, mira hacía delante para buscar bonus points.

Es raro … al final cuando los tests eran todos verdes me di cuenta que tenía un class pero no tenía nada que lo utilizaba. “Normalmente” cuando haces un programa a terminarlo puedes ver lo en todo su esplendor, funcionando bien … pero yo solo tenia los resultados de los tests.

OK (25 tests, 7 assertions)

:) curioso. Hice un script pequeño basado en los tests para echo los resultados.

La duda sobre TDD que tengo ahora es como tener confianza en los tests … e.g. ¿mis tests realmente cubren todos los caminos del código? Supongo que combinas TDD con hacer tests con la aplicación final para comprobar que funciona bien. Pero en éste caso de la kata no puedo hacer esas pruebas y solo puedo leer mis tests.