C�mo utilizar NUnit

Fecha: 09/Sep/2004 (27/Ago/04)
Autor: Giovanny Fernandez [email protected]

 

Actualmente la pauta en el desarrollo de software la marca la eficiencia, esto implica resultados r�pidos y de buena calidad. Una de las t�cnicas orientada a mejorar la eficiencia es la programaci�n extrema (XP). XP se basa fundamentalmente en dos premisas: escribir las pruebas primero y programaci�n por pares. La primera ha tra�do como resultado una metodolog�a denominada Desarrollo Dirigido por Pruebas (TDD, Test Driven Development). El presente articulo pretende adentrarse en el funcionamiento y utilizaci�n de NUnit, una herramienta utilizada para implementar TDD.

.

1. INTRODUCCI�N

Lo que hace tan efectiva la TDD es la automatizaci�n de las pruebas de programador, (programmer unit tests) y el hecho de que las herramientas para implementar esta t�cnica son gratis y totalmente funcionales.
NUnit es una de esas herramientas utilizada para escribir y ejecutar pruebas en .NET, NUnit es un framework desarrollado en C# que ofrece las funcionalidades necesarias para implementar pruebas en un proyecto. Adem�s provee una interfaz grafica para ejecutar y administrar las mismas.
 
El hecho de utilizar TDD implica 3 acciones: escribir las pruebas, escribir el c�digo que debe pasar las pruebas y refactorizar para eliminar el c�digo duplicado.
La primera se lleva a cabo de una manera sencilla y simple utilizando NUnit, NUnit soporta los lenguajes bases de .NET como C#, J#, VB y C++.


2. DESCRIPCION
 
NUnit es una herramienta que se encarga de analizar ensamblados generados por .NET, interpretar las pruebas inmersas en ellos y ejecutarlas. Utiliza atributos personalizados para interpretar las pruebas y provee adem�s m�todos para implementarlas. En general, NUnit compara valores esperados y valores generados, si estos son diferentes la prueba no pasa, caso contrario la prueba es exitosa.
NUnit carga en su entorno un ensamblado y cada vez que lo ejecuta, o mejor, ejecuta las pruebas que contiene, lo recarga. Esto es �til porque se pueden tener ciclos de codificaci�n y ejecuci�n de pruebas simult�neamente, as� cada vez que se compile no tiene que volver a cargar el ensamblado al entorno de NUnit si no que este siempre obtiene la �ltima versi�n del mismo.
NUnit ofrece una interface simple que informa si una prueba o un conjunto de pruebas fall�, pas� o fue ignorada.
La �ltima versi�n disponible de NUnit es la 2.2, que se encuentra en estado beta y la ultima versi�n estable es la 2.1, se pueden descargar de: http://www.nunit.org/download.html


3. FUNCIONAMIENTO

NUnit basa su funcionamiento en dos aspectos, el primero es la utilizaci�n de atributos personalizados. Estos atributos le indican al framework de NUnit que debe hacer con determinado m�todo o clase, es decir, estos atributos le indican a NUnit como interpretar y ejecutar las pruebas implementadas en el m�todo o clase.

El segundo son las aserciones, que no son mas que m�todos del framework de NUnit utilizados para comprobar y comparar valores.


3.1 ATRIBUTOS
La versi�n 1x de NUnit utilizaba las convenciones de nombrado del framework de .NET, pero desde la versi�n 2 en adelante NUnit usa atributos personalizados.
Dado que el framework de NUnit no deriva de otra clase o framework, el desarrollador puede elegir el nombre de la prueba a su antojo.
 
TestFixture
Este atributo se utiliza para indicar que una clase contiene m�todos de prueba. En versiones anteriores para poder utilizar este atributo se deb�a extender (heredar de) la clase TestCase, a partir de la versi�n 2 esto no es necesario, situaci�n que hace mucho m�s flexible el uso del atributo.
Existen algunas restricciones como por ejemplo que la clase debe tener un constructor por defecto y debe ser publica para que el framework NUnit pueda accederla.
 
Ejemplo:
 

#using <Nunit.Framework.dll>
using namespace System;
using namespace NUnit::Framework;
 
namespace NUnitTests
{
[TestFixture]
public __gc class SuccessTests
{
// ...
};
}
 
#include "cppsample.h"
 
namespace NUnitTests {
// ...
}
package NUnit.Tests;
 
import System.*;
import NUnit.Framework.TestFixture;
 
 
<font color = #008000>/** @attribute NUnit.Framework.TestFixture() */
public class SuccessTests
{
// ...
}
 
Imports System
Imports Nunit.Framework
Namespace Pruebas

<TestFixture()> Public Class PruebasProgramador 
'...
End Class
End Namespace
 


Test
Se utiliza para marcar un m�todo como m�todo de prueba, �ste no debe tener par�metros de entrada y debe retornar void (en el caso de visual Basic ser un sub) as� mismo la clase que lo alberga debe tener marcado el atributo TextFixture.
Ejemplo:
 

Imports System
Imports Nunit.Framework
Namespace Pruebas

<TestFixture()> Public Class PruebasProgramador
<Test()> Public Sub MetodoA()
' ...
End Sub
End Class
End Namespace


 


TestFixtureSetUp / TestFixtureTearDown
El primero de estos atributos se encarga de crear el ambiente de pruebas antes de ejecutarlas y el segundo se encarga de restaurar el ambiente despu�s de que las pruebas han sido ejecutadas. Van de la mano con los atributos Setup y TearDown, Setup es llamado antes de que se ejecute cualquier prueba. TearDown es llamado despu�s de que una prueba se ejecute.
Una clase marcada con TextFixture solo puede tener un m�todo marcado con TestFixtureSetUp y un solo m�todo marcado con TestFixtureTearDown, si existe mas de un m�todo marcado con estos atributos el proyecto compilara pero no se ejecutaran las pruebas. El orden de ejecuci�n es el siguiente:
 
 
 
 
 
 
 
 
 
 
ExpectedException
Este atributo como su nombre lo sugiere, tiene como funcionalidad indicar que la ejecuci�n de un m�todo prueba va a lanzar una excepci�n, el atributo tiene como par�metro el tipo de excepci�n que se espera que lance el m�todo, el framework ejecuta la prueba y si se genera una excepci�n del tipo especificado entonces la prueba es exitosa, si por el contrario se genera una excepci�n de tipo diferente al especifico la prueba no lo es. Esto es cierto aun cuando la excepci�n lanzada herede de la excepci�n esperada, es decir la excepci�n debe ser exactamente la especificada en el par�metro del atributo
Ejemplo:
 

namespace Pruebas
{
using System;
using NUnit.Framework;

[TestFixture]
public class Pruebas
{
[Test]
[ExpectedException(typeof(InvalidOperationException))]
public void GeneraExcepcion()
{ 
//... 
}
}
}

 

Imports System
Imports Nunit.Framework
 
Namespace Nunit.Tests
 
<TestFixture()> Public Class SuccessTests
<Test(), ExpectedException(GetType(Exception))>
Public Sub ExpectAnException()
' ...
End Sub
End Class
End Namespace


 

#using <Nunit.Framework.dll>
using namespace System;
using namespace NUnit::Framework;
 
namespace NUnitTests
{
[TestFixture]
public __gc class SuccessTests
{
[Test] [ExpectedException(__typeof(InvalidOperationException))]
void ExpectAnException();
};
}
 
#include "cppsample.h"
 
namespace NUnitTests {
// ...
}

 


Suite
El atributo suite es utilizado para definir subconjuntos de pruebas de acuerdo a las preferencias del usuario, sin embargo este atributo ha sido reemplazado desde la versi�n 2 debido al nuevo mecanismo din�mico de ejecuci�n de pruebas del framework (en modo gr�fico se puede seleccionar que pruebas se desean ejecutar utilizando el atributo category, adem�s se pueden agrupar dentro de una estructura marcada como TestFixture). En general es soportada para proveer compatibilidad hacia atr�s.
En las nuevas versiones del producto no se puede correr suites.
 
Category
 
El atributo category provee una alternativa a las suites para trabajar con grupos de pruebas. Cualquiera, ya sea casos de prueba individuales o Fixtures, pueden ser identificadas como pertenecientes a una categor�a de pruebas en particular. Ya sea en modo grafico o en modo consola se puede especificar que categor�as se excluyen o incluyen en la ejecuci�n. Cuando se utilizan categor�as, solo las pruebas de la categor�a seleccionada son ejecutadas. Las pruebas incluidas en las categor�as que se excluyen de la ejecuci�n no son reportadas.
Para excluir o incluir determinada categor�a en el modo consola incluya el par�metro /exclude o /include seguido del nombre de la categor�a. En el modo gr�fico existe una pesta�a denominada categor�as.
Es importante anotar que esta funcionalidad solo se encuentra presente en la versi�n 2.2 del producto. Este atributo puede utilizarse junto con TextFixture o Test
Ejemplos:
 

Imports System
Imports Nunit.Framework

Namespace Pruebas

<TestFixture(), Category("PruebasLargas")>
Public Class PruebasLargas1
'...
End Class
End Namespace


 

Imports System
Imports Nunit.Framework

Namespace Pruebas

<TestFixture()>
Public Class PruebasExitosas
<Test(), Category("Corta")> Public Sub PruebaCorta()
'...
End Sub
End Class
End Namespace

 


 
Explicit
Este atributo ocasiona que una prueba o un Fixture sean ignorados por el programa y no sean ejecutados a menos que sea especificado lo contrario. La prueba o Fixture ser� ejecutada si se selecciona directamente en la interfaz grafica de usuario, si su nombre es especificado en la l�nea de comandos, como el Fixture a ejecutar o si es incluido en una categor�a.
Si una prueba o un Fixture con el atributo Explicit es encontrado durante la ejecuci�n, el programa la ignora. El icono de la prueba o el Fixtures se coloca amarillo y es colocado en el reporte de pruebas no ejecutadas.
Esto es �til cuando se desea, por ejemplo ejecutar todas las pruebas menos una o unas. Sin embargo las pruebas marcadas con Explicit pueden ser ejecutadas si expl�citamente se le indica al programa que lo haga y esto se hace ya seleccionando la prueba y oprimiendo el bot�n run en el entorno gr�fico o escribi�ndola en la ventana de comandos.
 
Ejemplos:
 

namespace Pruebas
{
using System;
using NUnit.Framework;

[TestFixture, Explicit]
public class PruebaX
{
//...
}
}


 


 

namespace Pruebas
{
using System;
using NUnit.Framework;

[TestFixture]
public class PruebaX
{
[Test, Explicit]
public void PruebaExp()
{ 
//...
}
}
}


 


Ignore
Utilizado para indicar que se debe ignorar determinada prueba o Fixture, El programa ve el atributo y no ejecuta la prueba o las pruebas, el icono se coloca amarillo y la prueba es reportada como no ejecutada. Esto es �til para inhabilitar pruebas temporalmente, es decir, este atributo es �til para marcar una prueba o Fixture, si no se desea ejecutarla moment�neamente, en vez de comentar el m�todo o la clase, ya que de todas maneras va a ser compilada junto con el resto del c�digo pero no ser� tenida encuentra a la hora de ejecutar las pruebas.
Ejemplos:
 

Imports System
Imports Nunit.Framework

Namespace Pruebas

<TestFixture(), Ignore("Ignore un fixture")>
Public Class PruebasX
'...
End Class 
End Namespace


 

Imports System
Imports Nunit.Framework

Namespace Pruebas

<TestFixture()>
Public Class PruebasX
<Test(), Ignore("Ignore esta prueba")> Public Sub Ignorada()
'...
End Sub
End Class 
End Namespace

 


3.2 ASERCIONES
Las aserciones son m�todos est�ticos que la clase assert provee para realizar comparaciones y condiciones de prueba.
 
Comparaciones
Las aserciones mas utilizadas son las de comparaci�n, �stas reportan tanto el valor esperado como el valor actual. El valor esperado es siempre el primer par�metro en un m�todo assert, por ejemplo:

Assert.AreSame(object expected, object actual, string message );


En general se tiene dos m�todos sobrecargados: Assert.AreSame y AssertAreEqual, el primero verifica que el mismo objeto est� referenciado por ambos argumentos, es decir que las dos referencias a objetos apunten al mismo objeto, por ejemplo:
 

Assert.AreEqual (int expected, int actual, string message );


El Segundo esta sobrecargado para trabajar con la mayor�a de los tipos comunes(int, integer, double, single, string, etc.), por ejemplo
 

Assert.AreEqual(string expected, string actual, string message );


En una pr�xima versi�n se podr� comparar arreglos.
 
Es de anotar que los m�todos sobrecargados proveen la funcionalidad de comparar objetos de diferentes tipos y obtener el resultado apropiado, por ejemplo la siguiente prueba es exitosa:
 

Assert.AreEqual(3, 3.0, �Son Iguales� ); 


Condiciones de Prueba
Los m�todos que eval�an una condici�n se denominan de acuerdo a la condici�n. El valor a probar es el primer argumento y opcionalmente un mensaje como segundo.
 
Ejemplo:
 

Assert.IsTrue( bool condicion );
Assert.IsTrue( bool condicion, string mensaje );
Assert.IsFalse( bool condicion);
Assert.IsFalse( bool condicion, string mensaje );
Assert.IsNull( object unObjecto );
Assert.IsNull( object unObjecto, string mensaje );
Assert.IsNotNull( object unObjeto );
Assert.IsNotNull( object unObjeto, string mensaje );

 


Por ultimo tenemos el m�todo Assert.Fail que es utilizado para generar fallos que no son considerados por los otros m�todos.
 
 

 


4. UTILIZACI�N
 
4.1 INTERFACES
NUnit provee dos interfaces de usuario, la interfaz gr�fica y la interfaz de consola. Ambas pueden ser instanciadas desde la l�nea de comandos y la gr�fica se puede iniciar tambi�n haciendo doble clic sobre el icono en el escritorio.
 


Interfaz Gr�fica

Esta interface puede ejecutarse con o sin un nombre de ensamblado desde la ventana de comandos, en el caso que no se especifique ning�n ensamblado la aplicaci�n carga el ultimo ensamblado cargado.

� Para evitar este comportamiento se debe escribir: nunit-gui /noload, por el contrario si desea especificar un ensamblado o nombre de proyecto desde la l�nea de comandos escriba:
nunit-gui [nombreEnsamblado]
 
� Tambi�n puede abrir un proyecto de VisualStudio .NET:
nunit-gui [Proyecto]
 
� Para especificar un Fixture especifico de un ensamblado:
nunit.gui /fixture: [fixture] [ensamblado]

� Normalmente la GUI carga un ensamblado y entonces espera que el usuario le indique que ejecute las pruebas seleccionadas, si quiere que las pruebas se ejecuten inmediatamente teclee esto:
nunit-gui [ensamblado] /run
 
 
� Para especificar que configuraci�n desea cargar (debug/release) teclee:
nunit-gui [Provecto Visual Studio] /config: [configuracion]
La GUI no permite cargar mas de un ensamblado simult�neamente, para esto se debe cargar la soluci�n completa.

� Para obtener ayuda teclee:
nunit-gui /? � nunit-gui /help

Si desea hacer todo esto directamente en la interfaz grafica simplemente cargue el ensamblado y seleccione el Fixture o la prueba que desea ejecutar, o interactu� con el correspondiente men�
 


Interfaz Consola

El programa NUnit en modo consola no es agregado autom�ticamente al path del sistema as� que se debe hacer manualmente (nota al final del documento).
Esta interfaz provee algunas opciones adicionales, por ejemplo esta interface siempre crea una representaci�n XML de los resultados llamada �TestResult.xml�, la cual es generada en el direcorio de trabajo.

� A diferencia del modo grafico en la consola siempre se carga el ensamblado y se ejecutan las pruebas autom�ticamente:
nunit-console [ensamblado]
Donde [ensamblado] puede ser un ensamblado, un proyecto de VS.NET o un proyecto de NUnit.
 
� Para ejecutar solo un Fixture del ensamblado teclee:
 
nunit.console /fixture: [fixture] [ensamblado]

� Para especificar pruebas con categor�as a incluir o excluir teclee:
nunit-console [ensamblado] /include: [categor�a de pruebas]
nunit-console [ensamblado] /exclude: [categoria de pruebas]

� Es de anotar que include ejecuta solo las pruebas especificadas dentro de la categor�a, mientras que exclude como es l�gico ejecuta todas las pruebas menos las especificadas en la cl�usula. Por otro lado es posible utilizar estos comandos especificando varias categor�as, para hacer esto se debe separa las categor�as por comas.
Si desea guardar los resultados en un archivo de texto lo puede hacer de la siguiente manera:
 
nunit.console /out: [archivo] (version 2.2)
 
� Tambi�n lo puede hacer con el archivo de error generado por NUnit:
nunit-console nunit.tests.dll /err: [archivo] (version 2.2)
 
� Si desea especificar el nombre del archivo xml resultado de las pruebas teclee:
nunit-console /xml:[nombre.xml] [ensamblado]

� Para especificar la configuraci�n a ejecutar teclee:
nunit-console [ensamblado] /config: [Debug/Release]
Tenga en cuenta que esta opci�n no tiene efecto cuando se carga un ensamblado directamente.
 
� Para ejecutar las pruebas de varios ensamblados separe el nombre de estos con espacios:
nunit-console [ensamblado1] [ensamblado2 ] [ensamblado3]
Se pueden especificar multiples ensamblados pero no multiples proyectos de VS.Net o de NUnit
 


Otras opciones:
/wait le indica a NUnit que espere la entrada de usuario antes de salir.
/xmlconsole despliega xml puro en la consola, esto es �til cuando se esta depurando
 


4.2 IMPLEMENTANDO UNA PRUEBA
Mira en la siguiente pagina el ejemplo creado por la gente de NUnit. (he hecho algunos comentarios para adaptar el ejemplo a la versiones nuevas)
 


NOTA: Para configurar el path del sistema haga lo siguiente:
Clic derecho a Mi PC � propiedades � opciones avanzadas - variables de entorno � variables del sistema. Seleccione path y de clic en modificar, en el campo valor agregue esto al final: [; c:\Archivos de Programa\NUnit V2.1\bin] (sin los corchetes) y por ultimo acepte los cambios.
 


Ejemplo. Supongamos que hemos escrito una aplicaci�n bancaria y que tenemos una clase de dominio b�sica de Cuenta bancaria (Account). Account soporta operaciones para dep�sito (deposit), retiro (withdraw) y transferencia (transfer) de fondos. La clase ser�a algo similar a esto:
 


 

namespace bank
{
public class Account
{
private float balance;
public void Deposit(float amount)
{
balance+=amount;
}

public void Withdraw(float amount)
{
balance-=amount;
}
public void TransferFunds(Account destination, float amount)
{
}

public float Balance
{
get{ return balance;}
}
}
}


Ahora vamos a escribir una prueba para esta clase - AccountTest. El primer m�todo que probaremos ser� transferencia de fondos (TransferFunds).
 
 

namespace bank
{
using NUnit.Framework;

[TestFixture]
public class AccountTest
{
[Test]
public void TransferFunds()
{
Account source = new Account();
source.Deposit(200.00F);
Account destination = new Account();
destination.Deposit(150.00F);

source.TransferFunds(destination, 100.00F);
Assertion.AssertEquals(250.00F, destination.Balance);
Assertion.AssertEquals(100.00F, source.Balance);
}
}
}

 

 
Lo primero que se nota en esta clase es que posee un atributo asociado a ella llamado [TestFixture] � este es la forma de indicar que la clase contiene c�digo de prueba. Esta clase es p�blica (public) y adem�s cuenta con un constructor (el que provee el framework).

El �nico m�todo en la clase TransferFunds (Transferencia de fondos), posee el atributo [Test], esto indica que el m�todo es de prueba. Los m�todos de prueba deben retornar siempre void y no recibir par�metros. En nuestro m�todo de prueba hacemos las inicializaciones usuales de los objetos de prueba necesarios, ejecutamos el m�todo de negocio a ser probado y comprobamos el estado del objeto de negocio. La clase Assertion (Assert) define una colecci�n de m�todos usados para comprobar las condiciones posteriores a la ejecuci�n y en nuestro ejemplo usamos el m�todo AssertEquals (Assert.areEquals() en las nuevas versiones) para asegurarnos que luego de la transferencia, ambas cuentas posean los saldos correctos (existen varias sobrecargas a este m�todo, la versi�n que fue usada en este ejemplo posee los siguientes par�metros: el primer par�metro es un valor esperado y el segundo es el valor almacenado en el objeto).

Compila y ejecuta este ejemplo. Asumamos que compilaste tu clase de prueba como bank.dll. Ejecuta la GUI de NUnit (el instalador habr� creado un acceso directo en tu escritorio y en la carpeta Archivos de Programa), luego de haber iniciado el GUI, selecciona File�Open ,menu item, despl�zate hacia la ubicaci�n de tu archivo bank.dll y selecci�nalo en el cuadro de di�logo �Open�. Cuando la librer�a bank.dll se haya cargado, ver�s una estructura de �rbol para la prueba en el panel izquierdo y una colecci�n de paneles de estado a la derecha. Haz click en el bot�n Run, la barra de estado y el nodo TransferFunds en el �rbol de prueba se tornar�n rojos � nuestra prueba ha fallado. El panel �Errors and Failures� mostrar� el siguiente mensaje � �TransferFunds : expected <250> but was <150>� y el panel de stack trace justo abajo reportar� en que lugar en el c�digo de prueba ocurri� el error- �at bank.AccountTest.TransferFunds() in C:\nunit\BankSampleTests\AccountTest.cs:line 17�

Ese es un comportamiento esperado, la prueba ha fallado debido a que no hemos implementado el m�todo TransferFunds a�n. Ahora hag�moslo funcionar. No cierres el GUI, vuelve a tu IDE y corrige el c�digo, c�mbialo as�:
 

public void TransferFunds(Account destination, float amount)
{
destination.Deposit(amount);
Withdraw(amount);
}


Ahora recompila tu c�digo y haz click en el bot�n run en la GUI nuevamente � la barra de estado y el �rbol de pruebas se tornar�n verdes. (Nota como el GUI ha recargado el assembly autom�ticamente); mantendremos el GUI abierto todo el tiempo y continuaremos trabajando con nuestro c�digo en el IDE y escribiremos m�s pruebas.

Ahora a�adiremos algo de control de errores al c�digo de Account. Estamos agregando el requerimiento de saldo m�nimo a la cuenta para estar seguros de que los bancos contin�en haciendo su dinero obligando a mantener un saldo m�nimo. A�adiremos la propiedad de saldo m�nimo a nuestra clase Account.
 

private float minimumBalance = 10.00F;
public float MinimumBalance
{
get{ return minimumBalance;}
}

 

 
Ahora usaremos una excepci�n para indicar la falta de fondos:
 

namespace bank
{
using System;
public class InsufficientFundsException : ApplicationException
{
}
}

 

 
Agrega ahora un nuevo m�todo de prueba a la clase AccountTest:
 
 

[Test]
[ExpectedException(typeof(InsufficientFundsException))]
public void TransferWithInsufficientFunds()
{
Account source = new Account();
source.Deposit(200.00F);
Account destination = new Account();
destination.Deposit(150.00F);

source.TransferFunds(destination, 300.00F);
}

 


Este m�todo de prueba adem�s del atributo [Test] posee otro llamado [ExpectedException] - esta es la forma de indicar que el c�digo de prueba est� esperando una excepci�n de cierto tipo; si tal excepci�n no ocurre durante la ejecuci�n � la prueba fallar�. Compila tu c�digo y regresa a la GUI. Mientras compilabas tu c�digo de prueba, la GUI se debi� tornar de color gris y habr� colapsado el �rbol como si las pruebas no hubiesen sido ejecutadas a�n (la GUI espera por cambios hechos en los assemblies de prueba y se actualiza a si misma cuando la estructura del �rbol de prueba cambia � Ej.: cuando se ha agregado una nueva prueba). Haz click en el bot�n Run � ahora tenemos una barra de estado roja nuevamente. Tenemos la misma falla: �TransferWithInsufficentFunds : InsufficientFundsException was expected�. Corrijamos nuestro c�digo de Account nuevamente, modifiquemos el m�todo TransferFunds de la siguiente forma:
 

public void TransferFunds(Account destination, float amount)
{
destination.Deposit(amount);
if(balance-amount<minimumBalance) throw new InsufficientFundsException();
Withdraw(amount);
}

 

 
Compila y ejecuta las pruebas � ver�s una barra verde. La prueba fue exitosa! Pero espera, mirando al c�digo que hemos escrito nos podemos dar cuenta que el banco podr�a estar perdiendo dinero en cada operaci�n fallida de Transferencia de fondos. Escribamos una prueba para confirmar nuestra sospecha. A�ade este m�todo de prueba:
 

[Test]
public void TransferWithInsufficientFundsAtomicity()
{
Account source = new Account();
source.Deposit(200.00F);
Account destination = new Account();
destination.Deposit(150.00F);

try
{
source.TransferFunds(destination, 300.00F);
}
catch(InsufficientFundsException expected)
{
}

Assertion.AssertEquals(200.00F,source.Balance);
Assertion.AssertEquals(150.00F,destination.Balance);
}

 


Estamos probando la propiedad transaccional de nuestro m�todo de negocio � todas las operaciones han sido exitosas o ninguna. Compila y ejecuta � Ver�s una barra roja. Veamos, hemos obtenido $300.00 de una manera muy f�cil (D�j� vu de 1999.com?) � la cuenta de origen tiene el saldo correcto de $150.00 pero la cuenta de destino muestra: $450.00. �C�mo corregimos esto?. Podemos simplemente mover la comprobaci�n de saldo m�nimo antes de las transacciones:
 

public void TransferFunds(Account destination, float amount)
{
if(balance-amount<minimumBalance) throw new InsufficientFundsException();
destination.Deposit(amount);
Withdraw(amount);
}

 

 
�Qu� tal si el m�todo de retiro Withdraw() lanza otra excepci�n? �Deber�amos ejecutar una transacci�n de compensaci�n en el bloque del catch o confiar en nuestro transaction manager para restaurar el estado de los objetos? Necesitamos contestar estar preguntas en cierto punto, pero no ahora; pero que hacemos con la prueba fallida mientras tanto � �Quitarla? Una mejor manera es ignorarla temporalmente, a�ade el siguiente atributo a tu m�todo de prueba:
 

[Test]
[Ignore("Se necesita decidir como implementar el manejo transaccional en la aplicaci�n")]
public void TransferWithInsufficientFundsAtomicity()
{ el mismo c�digo}

 


Compila y ejecuta � Ver�s una barra amarilla. Haz click en la vi�eta �Tests Not Run� y ver�s: bank.AccountTest.TransferWithInsufficientFundsAtomicity() en la lista con la raz�n por la cual la prueba es ignorada.

Al ver nuestro c�digo de prueba nos damos cuenta que se puede hacer algo de refactorizaci�n. Todos los m�todos comparten un conjunto com�n de objetos de prueba. Extraigamos el c�digo de inicializaci�n a un m�todo de SetUp y reus�moslo en todas nuestras pruebas. La versi�n refactorizada de nuestra clase de prueba ser�a:
 

namespace bank
{
using System;
using NUnit.Framework;


[TestFixture]
public class AccountTest
{
Account source;
Account destination;

[SetUp]
public void Init()
{
source = new Account();
source.Deposit(200.00F);
destination = new Account();
destination.Deposit(150.00F);
}

[Test]
public void TransferFunds()
{
source.TransferFunds(destination, 100.00f);
Assertion.AssertEquals(250.00F, destination.Balance);
Assertion.AssertEquals(100.00F, source.Balance);
}

[Test]
[ExpectedException(typeof(InsufficientFundsException))]
public void TransferWithInsufficientFunds()
{
source.TransferFunds(destination, 300.00F);

}

[Test]
[Ignore("Se necesita decidir como implementar el manejo transaccional en la aplicaci�n ")]
public void TransferWithInsufficientFundsAtomicity()
{
try
{
source.TransferFunds(destination, 300.00F);
}
catch(InsufficientFundsException expected)
{
}

Assertion.AssertEquals(200.00F,source.Balance);
Assertion.AssertEquals(150.00F,destination.Balance);
}
}
}

 


Nota que el m�todo Init tiene el c�digo com�n de inicializaci�n, posee tipo de retorno void, sin par�metros, y est� marcado con el atributo [SetUp]. Compila y ejecuta- vas a ver la misma barra amarilla!

Es de anotar que NUnit que puedes hacer debug asociando NUnit al proceso de depuraci�n de Visual Studio, de esta manera es posible ejecutar las pruebas y hacer el seguimiento al programa al mismo tiempo. Para hacer esto inicie NUnit, en VisualStudio de clic en el men� herramientas -proceso de depuraci�n y seleccione NUnit, a continuaci�n puede trabajar con todas las facilidades de debug que proporciona el IDE. Por ultimo tenga en cuenta que cada vez que recompile el c�digo tendr� que volver a asociar NUnit al IDE.
 

 


ir al índice