jueves, mayo 31, 2007

TDD (El test antes del código) (y 3)

Cogemos el test 1: Dado un -1 (ejemplo de entero negativo) y 2 (ejemplo de entero positivo), obtenemos una excepción (cumplimos la regla de negocio 2)

Codificamos el test:

using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;


[TestFixture]
public class CalculadoraTest
{
[Test, ExpectedException()]
public void Calculadora_Test_001()
{
Calculadora calc = new Calculadora();
calc.sumar(-1, 1);
}
}




Y codificamos lo mínimo para que funcione el test (que funcione no significa que pase):

public int sumar(int a, int b)
{
return 0;
}
}


El tets falla. Evidente, no? Esperabamos una excepción y hemos recibido un 0. Rehacemos el código hasta que pase el test.

public int sumar(int a, int b)
{
if (a < 0)
throw new Exception();
return 0;
}


Ahora pasa. Perfecto. Cogemos el segundo test.

Dado un 1 (ejemplo de entero positivo) y un -1 (ejemplo de entero negativo), obtenemos una excepción (cumplimos la regla de negocio 2)

Codificamos el test, comprobamos que falla…

[Test, ExpectedException()]
public void Calculadora_Test_002()
{
Calculadora calc = new Calculadora();
calc.sumar(1, -1);
}


Y cambiamos el código para que también soporte este caso.

public int sumar(int a, int b)
{
if (a < 0 b <0)
throw new Exception();
return 0;
}


Ahora pasa. Genial, pero no hemos acabado. Lanzamos de nuevo TODOS los tests para ver que el cambio no rompe algo que funcionaba.
¿Funcionan? Si, genial. Antes de ir al siguiente código, miramos a ver si se puede refactorizar algo…
¿Crees que aún es pronto? ¿Qué hay pocas líneas? Jaja Vemos que en los dos tests que hay hasta ahora, creamos un objeto Calculadora. Podríamos sacarlo de allí y meterlo a nivel general.
El código quedaría así:

[TestFixture]
public class CalculadoraTest
{
Calculadora calc;

[TestFixtureSetUp]
public void Init()
{
calc = new Calculadora();
}

[Test, ExpectedException()]
public void Calculadora_Test_001()
{
calc.sumar(-1, 1);
}

[Test, ExpectedException()]
public void Calculadora_Test_002()
{

calc.sumar(1, -1);
}
}


Cogemos el test 3: Dado un 1 (ejemplo de entero positivo) y un 3 (ejemplo de entero positivo), obtenemos un 4 (cumplimos la regla de negocio 1 y la 3). Repetimos los pasos anteriores…

Y falla… Bueno, corregimos el código para que pase (OJO a la jugada). Vamos a hacer que siempre devuelva un 4 (salvo que alguno sea negativo).

El test queda:

[Test]
public void Calculadora_Test_003()
{
Assert.IsTrue(calc.sumar(1, 3) == 4);
}


Y el código queda:
public int sumar(int a, int b)
{
if (a < 0 b <0)
throw new Exception();
return 4;
}



Parece que la jugada no tiene sentido, pero paciencia. De momento, no hemos metido ni una función demás en el código. Hace lo que le piden los test. Ni más, ni menos.

Cogemos el 4º test. Dado un 0 (ejemplo de frontera) y un 1 (ejemplo de entero positivo), obtenemos un 1 (cumplimos la regla de negocio 1 y la 3). Repetimos el proceso.
Ahora hacemos que devuelva siempre 2.

public int sumar(int a, int b)
{
if (a < 0 b <0)
throw new Exception();
return 2;
}


El test pasa pero si ejecutamos todos no. Es ahora cuando metemos el a + b.


Y pasan todos los test… genial.

Y así sucesivamente hasta el test 7 (incluido). Pasar estos tests no requerirá cambios en el código de la calculadora, pero el 8º sí.

Dado un 10001 (ejemplo de frontera numero grande) y 1 (ejemplo de entero positivo), obtenemos una excepción (cumplimos la regla de negocio 4). Esto requiere que metamos otra rama en los primeros IF.

Y así sucesivamente… nuevo test, que pase, refactorizamos, nuevo test, que pase, refactorizamos, nuevo test, que pase, refactorizamos, …

Al final nos queda la clase de test así:


[TestFixture]
public class CalculadoraTest
{
Calculadora calc;

[TestFixtureSetUp]
public void Init()
{
calc = new Calculadora();
}

[Test, ExpectedException()]
public void Calculadora_Test_001()
{
calc.sumar(-1, 1);
}

[Test, ExpectedException()]
public void Calculadora_Test_002()
{
calc.sumar(1, -1);
}

[Test]
public void Calculadora_Test_003()
{
Assert.IsTrue(calc.sumar(1, 3) == 4);
}

[Test]
public void Calculadora_Test_004()
{
Assert.IsTrue(calc.sumar(1, 1) == 2);
}

[Test]
public void Calculadora_Test_005()
{
Assert.IsTrue(calc.sumar(1, 0) == 1);
}

[Test]
public void Calculadora_Test_006()
{
Assert.IsTrue(calc.sumar(10000, 1) == 10001);
}

[Test]
public void Calculadora_Test_007()
{
Assert.IsTrue(calc.sumar(1, 10000) == 10001);
}

[Test, ExpectedException()]
public void Calculadora_Test_008()
{
calc.sumar(10001, 1);
}

[Test, ExpectedException()]
public void Calculadora_Test_009()
{
calc.sumar(1, 10001);
}

[Test]
public void Calculadora_Test_010()
{
Assert.IsTrue(calc.sumar(9999, 1) == 10000);
}

[Test]
public void Calculadora_Test_011()
{
Assert.IsTrue(calc.sumar(1, 9999) == 10000);
}
}


Y el código…

public int sumar(int a, int b)
{
if (a <> 10000 a > 10000)
throw new Exception();
return a + b;
}



Curioso que hayamos dedicado más de 50 líneas para testear 3, no? Puede parecer poco rentable, pero AHORA SABEMOS QUE EL CÓDIGO FUNCIONA Y CUMPLE LAS REGLAS DE NEGOCIO. A PARTIR DE AHORA, SI AÑADIMOS MÁS CÓDIGO, SABREMOS QUE EL FALLO ES DE LO QUE VAYAMOS AÑADIENDO, PORQUE EL CÓDIGO DE A SUMA, ESTÁ PROBADO.

Un saludo

3 comentarios:

Anónimo dijo...

Predilection casinos? into this unfinished [url=http://www.realcazinoz.com]casino[/url] superintend and origination online casino games like slots, blackjack, roulette, baccarat and more at www.realcazinoz.com .
you can also about our additional [url=http://freecasinogames2010.webs.com]casino[/url] orientate at http://freecasinogames2010.webs.com and catch verifiable incredibly lonely !
another boaster [url=http://www.ttittancasino.com]casino spiele[/url] concatenation of events is www.ttittancasino.com , as opposed to of german gamblers, get unconstrained online casino bonus.

Anónimo dijo...

You could easily be making money online in the undercover world of [URL=http://www.www.blackhatmoneymaker.com]blackhat seo[/URL], Don’t feel silly if you have no clue about blackhat marketing. Blackhat marketing uses little-known or little-understood methods to generate an income online.

Anónimo dijo...

These are a bit Spartan term in Einsteinian universe and all in all extended for a bank cataloging and fill in some forms. [url=http://paydayloanscoolp.co.uk]payday loans[/url] Commercial or acting payday loans are for agnate who not have pals and ancestors members which have Spartan bucks to lend you. You could ask for a cash advance from your accept for gospel card provider; be able to administer our financial needs.