Cómo utilizar NUnit

Fecha: 09/Sep/2004 (27/Ago/04)
Autor: Giovanny Fernandez gfernandez@heinsohn.com.co

 

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