miércoles, 18 de julio de 2012

BDD & .NET = SpecFlow

Llevo tiempo detrás del XP, y todo lo que lo rodea, aprendiendo por mi cuenta TDD, patrones, buscando la excelencia técnica (que no se consigue con certificaciones, que las respuestas están puestas en internet), es decir, leyendo libros técnicos, viendo lo que otros han hecho y sobre todo programando (Katas, y código empresarial).

Ahora le toca al BDD. Me he visto y he practicado con este  vídeo. La verdad es que ahora entiendo un poco más lo que es, pero todavía me falta bastante por aprender.
Es importante tener instalado el SpecFlow , junto con el visual studio (en mi caso fue el monodevelop) en el sistema (en caso fue xubuntu 12.04), para poder hacerlo.Dejo el código resultante.
Primeramente la características (feature), el escanario que vas a testear.

Feature: Scoring
 In order to keep track of my score
 As a bowler
 I want to use automatic scoring system for some feedback
 
Scenario: Bowling a strike
 Given I am on the first frame
 When I bowl a strike
 Then I see a "X" and a message that says "Good Job!"
 And I Should hear "Green Day"

Scenario: Bowling a gutter ball as a first throw
 Given I am on the first frame
 When I bowl a gutter ball
 Then I should see an "0" and a message that says "You need lessons"

Scenario: Bowling a gutter balls in a frame
 Given I hace bowled a gutter ball already
 When I bowl another gutter ball
 Then I should see an "0" and a message that says "You need lessons"

Scenario: Finishing the game with nothing but gutter balls
 Given I bowled a gutter ball on every frame
 Then I should see an "0" and a message that says "you need lessons"
 And I Should hear "Sad Trombone"

Código que testea
using System;
using NUnit.Framework;
using TechTalk.SpecFlow;
using SuperBowlingScorer;

namespace Spec
{
 [Binding]
    public class ScoringSteps
 {
  SuperScorer _scorer;
  [Given(@"I am on the first frame")]
  public void GivenIamOnTheFirstFrame ()
  {
   _scorer = new SuperScorer ();
   Assert.AreEqual (1, _scorer.Frame);
  }

  [When(@"I bowl a strike")]
  public void WhenIBowlAStrike ()
  {
   _scorer.ScoreFirstBall (10);
  }

  [Given(@"I have bowled a gutter ball already")]
  public void WhenIHaveBowledAGutterBallAlready ()
  {
   _scorer = new SuperScorer ();
   _scorer.ScoreFirstBall (0);
  }
  
  [Then(@"I see a ""(.*)"" and a message that says ""(.*)""")]
  public void ThenISeeAXAndAMessageThatSaysGobJob (string score, string message)
  {
   Assert.AreEqual (message, _scorer.BowlerMessage);
   Assert.AreEqual (score, _scorer.Score);
  }
  
  [Then(@"I should hear  ""(.*)""")]
  public void ThenIShouldHearGreenDay (string song)
  {
   Assert.AreEqual (song, _scorer.SongToPlay);
  }
  
  [When(@"I bowl a gutter ball")]
  public void WhenIBowlAGutterBall ()
  {
   _scorer.ScoreFirstBall (0);
  }
  
  
  
  [When(@"I bowl another gutter ball")]
  public void WhenIBowlAnotherGutterBall ()
  {
   ScenarioContext.Current.Pending ();
  }
  
  
  [Given(@"I bowled a gutter ball on every frame")]
  public void GivenIBowledAGutterBallOnEveryFrame ()
  {
   _scorer = new SuperScorer ();
   for (int i = 1; i < 10; i++) {
    _scorer.ScoreFirstBall (0);
    _scorer.ScoreSecondBall (0);
   }
   
  }
 }
}
  

Código que implementa las funcionalidad a testear (S.U.T.)
using System;

namespace SuperBowlingScorer
{
 public class SuperScorer
 {
  public int Frame {
   get;
   set;
  }
  
  public string BowlerMessage {
   get;
   set;
  }
  
  public string Score {
   get;
   set;
  }
  
  public string  SongToPlay {
   get;
   set;
  }
  
  
  
  public int PinsTotal {
   get;
   set;
  }
  
  public int FirstBallScore {
   get;
   set;
  }
  
  
  public SuperScorer ()
  {
   Frame = 1;
  }
  
  public void ScoreSecondBall (int pinsKnockedDown)
  {
   PinsTotal += pinsKnockedDown;
   if (Frame < 10) {
    Frame ++;
   }
   
   if (IsGutterBall (pinsKnockedDown) && (FirstBallScore == 0)) {
    BowlerMessage = "You need lessons";
    Score = "0";
   }
   
   if ((Frame == 10)
    && (PinsTotal == 0)) {
    BowlerMessage = "You need the gutter bumpers";
    Score = "0";
    SongToPlay = "Sad Trombone";
   } 
  }
  
  public bool IsGutterBall (int pinsKnockDown)
  {
   return pinsKnockDown == 0;
  }
  
  public bool IsStrike (bool isFirstBall, int pinsKnockedDown)
  {
   return isFirstBall && (pinsKnockedDown == 10);
   
  }
  
  public void ScoreFirstBall (int pinsKnockDown)
  {
   if (IsStrike (true, pinsKnockDown)) {
    BowlerMessage = "Good Job!";
    Score = "X";
    SongToPlay = "Green Day";
   } else if (IsGutterBall (pinsKnockDown)) {
    BowlerMessage = "You'll better next time";
    Score = "0";   
   }
   FirstBallScore = pinsKnockDown; 
   PinsTotal += pinsKnockDown;
  }
 }
}
Creo que puede ayudar mucho a testear las aplicaciones y dar más calidad a los productos. Tengo que seguir investigando ...

No hay comentarios:

Publicar un comentario