IDisposable Thoughts

Honey… where is my coding t-shirt?

Hey there! Thanks for dropping by Theme Preview! Take a look around
and grab the RSS feed to stay updated. See you around!

Posts Tagged ‘xunit’

Moq e Indexers

Mi framework favorita de mocking es Moq, es flexible, rápida, intuitiva, (dije flexible ya verdad?). Otro día hablaré más detallado de Moq y sus destrezas. Hoy un compañero de trabajo se topó con algo interesante en un test, el mock de una propiedad indexer. Como recordaran, un indexer no es más que una propiedad de una clase que se comporta como la “llave” de esa propiedad, “a-la” diccionario.

La buena noticia es que Moq me permite fácilmente crear mocks de indexers.

Digamos que tenemos la siguiente clase e interface en cuestión:

interface ISimpleStorage {
    string this[string key] { get; set; }
}

interface ISearchDataFiller {
    void FillData(SearchData data);
}

class ClientIPSearchFiller : ISearchDataFiller {
    public readonly string HttpRemoteHostKey = "HTTP_REMOTE_HOST";
    public readonly string RemoteHostKey = "REMOTE_HOST";
    private readonly ISimpleStorage _storage;

    public ClientIPSearchDataFiller(ISimpleStorage storage) {
        _storage = storage;
    }

    public void FillData(SearchData data) {
          var ip = _storage[HttpRemoteHostKey] ?? string.Empty;
                if (string.IsNullOrEmpty(ip))
                    ip = _storage[RemoteHostKey] ?? string.Empty;
                data.IpAddress = ip;
    }
}

Gracias a Moq nuestro test sería algo tan simple como esto (faltan facts, pero ya ustedes se hicieron a la idea :P )

class ClientIPSearchFillerFacts {
    private readonly ClientIPSearchFiller _filler;
    private readonly Mock<ISimpleStorage> _storage;

    public ClientIPSearchFillerFacts() {
        _storage = new Mock<ISimpleStorage>();
        _filler = new ClientIPSearchFiller(_storage.Object);
    }

    [Fact]
    public void When_http_remote_host_appears_use_it() {
        const string ip = "192.168.1.1";
        var data = new SearchData();
        _storage.SetupGet(x => x[data.HttpRemoteHostKey]).Returns(ip);
        _filler.FillData(data);

        _storage.VerifyAll();
        data.IpAddres.Should().Be.EqualTo(ip);
    }

    [Fact]
    public void When_http_remote_host_is_empty_use_remote_host() {
        const string ip = "192.168.1.1";
        var data = new SearchData();
        _storage.SetupGet(x => x[data.HttpRemoteHostKey]).Returns(string.Empty);
        _storage.SetupGet(x => x[data.RemoteHostKey]).Returns(ip)
        _filler.FillData(data);

        _storage.VerifyAll();
        data.IpAddres.Should().Be.EqualTo(ip);
    }
}

Fácil, rápido, simple.

Hasta la próxima!

Es bastante común toparnos con casos en los que debemos asegurarnos que el mismo test se cumpla para varias condiciones. Imagínense el desarrollo de una calculadora o mucho mejor, el de alguna pieza de lógica de negocio dependiente de data. En vez de escribir ciclos dentro de nuestro test o peor aún, escribir varios test para el caso, en XUnit.NET tenemos el apoyo de las “Theory” que son test que estan fuertemente ligados a los datos.

Los datos son pasados como parámetros del test y el origen de los datos depende de nuestro proveedor de datos seleccionado. En XUnit.NET Extensions tenemos de “cajita” varios proveedores de datos que podemos usar:

  • InlineDataAttribute, los datos se presentan en línea en cada atributo
  • ClassDataAttribute, los datos son proporcionados por una clase que implementa IEnumerable<T>
  • PropertyDataAttribute, los datos son entregados por la propiedad de una clase que retorna IEnumerable<T>
  • SqlServerDataAttribute, los datos vienen de una consulta de una base de datos de SQL Server
  • OleDbDataAttribute, los datos tienen como origen una consulta de un proveedor OleDb
  • ExcelDataAttribute, los datos tienen como origen una hoja de cálculo de Excel.

El uso de Theory y DataAttribute proporciona una agilidad increíble al probar ciertas condiciones que antes requeririan mucha más pericia. Depende de nosotros sacarle provecho :)

[Theory]
[InlineData(1, 2, 3)]
[InlineData(4, 5, 9)]
public void It_can_use_correctly_the_data_attribute(int a, int b, int result)
{
    Assert.Equal(result, (a + b));
}

[Theory, ExcelData("myTestData.xls", "SELECT a, b, result FROM Data")]
public void It_can_use_correctly_the_data_from_an_excel_file(int a, int b, int result)
{
    Assert.Equal(result, (a + b));
}

Bien, hasta aquí llegamos con las Extensiones de XUnit.NET, la próxima entrega veremos como extender a nuestro antojo XUnit.NET ;)

FreezeClock es uno de esos atributos maravillosos de XUnit.NET, nos permite “congelar” el reloj (tal como lo dice su nombre) en un tiempo dado y de esa manera comprobar que operaciones que dependen de tiempo se lleven acabo exitosamente. En versiones anteriores a la 1.5 FreezeClock cambiaba el tiempo mostrado por DateTime.Now, pero esto causaba problemas con ciertas implementaciones, así que en XUnit.NET 1.5 se debe utilizar la clase Clock y su propiedad Now (Clock.Now) en vez de DateTime.Now para efectos de las pruebas, de igual manera podríamos ver a Clock.Now como un clon de DateTime.Now en todos sus sentidos.

[Fact]
public void It_should_fail_because_clock_are_not_frozen()
{
    var clock1 = Clock.Now;
    Thread.Sleep(1000);
    var clock2 = Clock.Now;
    Assert.NotEqual(clock1, clock2);
}

[Fact, FreezeClock]
public void It_should_pass_because_clock_are_frozen()
{
    var clock1 = Clock.Now;
    Thread.Sleep(1000);
    var clock2 = Clock.Now;
    Assert.Equal(clock1, clock2);
}

[Fact]
public void Clock_time_must_be_lesser_than_a_second_different_from_now()
{
    var now = DateTime.Now;
    var clock = Clock.Now;
    Assert.True((clock - now).Milliseconds < 1000);
}

A veces es necesario (por alguna razón extraña), mostrar el inicio y el fin de un test en la consola, con el tiempo de inicio y tiempo de fin (imaginémonos un test de performance sencillo); para esos menesteres tenemos a nuestro amigo TraceAttribute, que no hace más que enviar a la salida Trace el inicio y el fin del test, un atributo sencillo de entender.

[Fact, Trace]
public void Must_sent_to_trace_console_start_and_end_time_of_test()
{
    Assert.True(true);
}
AutoRollbackAttribute

Comunmente cuando trabajamos con bases de datos, es bastante común el toparnos con transacciones, o mejor aún, toparnos con código que para simplificarnos las cosas debería correr dentro de una transacción. Por ejemplo, un test contra la base de datos que haga ciertos inserts, pero al final del test no nos importa el resultado y simplemente descartamos la transacción, por lo tanto nada fue insertado o modificado en la base de datos. Para esas tareas tenemos al atributo AutoRollbackAttribute, que simplemente al inicio del test crea una transacción y al final del test descarta la transacción. Es dificil probar código transaccional, pero con la “descripción” de que realiza el test, simplemente podemos ver si hay o no una transacción creada.

// NOTE: It Requires referece to System.Transactions
[Fact]
public void When_no_autorollback_is_present_there_is_no_transaction()
{
    Assert.Null(Transaction.Current);
}

[Fact, AutoRollback]
public void When_autorollback_is_present_there_is_a_transaction()
{
    Assert.NotNull(Transaction.Current);
}

XUnit.NET Extensions, AssumeIdentity

Una de las excelentes características y habilidades de XUnit.NET es su capacidad de ser extendido en muchas formas. Como parte del “paquete” de XUnit.NET, se incluye una librería adicional con atributos extras para cambiar en cierta manera el comportamiento de un test mientras realizamos las pruebas. A esta librería se le llama XUnit.NET Extensions y viene incluída con el download de XUnit.NET. Veremos algunos de los atributos extras incluídos con XUnit.NET Extensions.

El primero en ver será AssumeIdentity, este atributo permite cambiar el Principal de la actual Thread de ejecución y agregarle el rol indicado por el atributo. Por defecto la thread de ejecución del test corre bajo el principal con la identity de “xunit”.

[Fact]
public void It_should_fail_because_user_has_no_role()
{
    Assert.False(Thread.CurrentPrincipal.IsInRole("fake_role"));
}

[Fact]
[AssumeIdentity("fake_role")]
public void It_should_pass_because_user_is_in_role()
{
    Assert.True(Thread.CurrentPrincipal.IsInRole("fake_role"));
}

Voilà! Luego converaremos de los otros atributos disponibles en este namespace.

XUnit.NET y las Excepciones

El día de ayer publiqué mi primer post corto acerca de XUnit.Net, e inmediatamente después alguien me hizo una pregunta, la cuál parafraseando va algo así:

“Puedo testear o ver el mensaje retornado por la excepción y así asegurarme que es una excepción específica”

No voy a discutir si esto esta bien o mal (en cuanto a la especificidad de la excepción), pero me parece interesante la pregunta. Como mencionamos ayer, podemos probar que una excepción es arrojada mediante el método “Throws” de la clase Assert:

public void ThrowOperation()
{
    throw new InvalidOperationException("My message");
}

[Fact]
public void TestAssertWithException()
{
    Assert.Throws<InvalidOperationException>(() => ThrowOperation());
}

El detalle es que Assert.Throws no solamente se asegura que la excepción fue arrojada, sino que efectivamente retorna la excepción al sistema como un retorno más, de esta manera podemos hacer cosas como:

public void ThrowOperation()
{
    throw new InvalidOperationException("My message");
}

[Fact]
public void TestAssertWithMessage()
{
    var ex = Assert.Throws<InvalidOperationException>(() => ThrowOperation());
    Assert.Equal("My message", ex.Message);
}

De esta manera no sólo podemos probar que la excepción es efectivamente arrojada, sino que también podemos probar sin ningún problema otros atributos de la excepción como tal. ¿Interesante verdad?

Cómo siempre, cualquier pregunta o comentario somos oidos abiertos :)

XUnit.NET y las Colecciones

Continuando con mi corta serie acerca de XUnit, algo que es sumamente útil en las pruebas es verificar si un item se encuentra o no en una colección. En XUnit.Net esto es sumamente fácil, simplemente usamos los métodos Contains y DoesNotContains los cuales también funcionan con strings.

private readonly int[] numbers = {1, 2, 3, 4, 5, 6};

[Fact]
public void It_must_return_true_if_number_is_in_collection()
{
    Assert.Contains(1, numbers);
}

[Fact]
public void It_must_return_true_if_number_is_not_in_collection()
{
    Assert.DoesNotContain(7, numbers);
}

[Fact]
public void It_must_return_true_if_string_contains_substring()
{
    Assert.Contains("hola", "hola mundo");
}

[Fact]
public void It_must_return_true_if_string_does_not_contains_substring()
{
    Assert.DoesNotContain("adios", "hola mundo");
}

De igual manera tenemos métodos para verificar si una colección se encuentra vacía o no, obviamente nuestros métodos en cuestion seran Empty y NotEmpty (estos no funcionan con strings).

private int[] numbers = { 1, 2, 3, 4, 5, 6 };

[Fact]
public void It_must_return_true_if_collection_is_not_empty()
{
    Assert.NotEmpty(numbers);
}

[Fact]
public void It_must_return_true_if_collection_is_empty()
{
    int[] empty = {};
    Assert.Empty(empty);
}

XUnit.NET y un par de Assert extras

Un par de Assert’s extras que vienen con XUnit.NET y son sumamente útiles, son aquellos capaces de trabajar con rangos, y estos pueden usar nuestros IComparer<T>, como siempre, nada explica mejor que un FactSet

[Fact]
public void It_must_assert_number_is_in_a_range_of_numbers()
{
    Assert.InRange(1, 1, 3);
    Assert.InRange(2, 1, 3);
    Assert.InRange(3, 1, 3);
    Assert.NotInRange(4, 1, 3);
    Assert.NotInRange(0, 1, 3);
}

[Fact]
public void It_must_assert_letter_is_in_a_range_of_letters()
{
    Assert.InRange("a", "a", "d");
    Assert.NotInRange("e", "a", "d");
    Assert.NotInRange("B", "a", "b");
    Assert.InRange("B", "a", "b", StringComparer.InvariantCultureIgnoreCase);
}

Otro aspecto que solemos probar es si una instancia es asignable, del tipo o derivada (implementada) a partir de otro tipo, en otras palabras, si hereda o implementa a alguien más. Esto es facil con IsType e IsAssignableFrom

[Fact]
public void It_must_assert_object_is_of_same_type()
{
    var item = new MySimpleEntity();
    Assert.IsType<MySimpleEntity>(item);
    Assert.IsNotType<IDoable>(item);
}

[Fact]
public void It_must_assert_object_is_assignable_from_type()
{
    var item = new MySimpleEntity();
    Assert.IsAssignableFrom<IDoable>(item);
}

Y por último, a veces necesitamos probar que una instancia representa la misma instancia que otra, no precisamente que es “igual”, esto lo logramos con “Same”:

[Fact]
public void It_must_assert_object_is_the_same_instance()
{
    var item = new MySimpleEntity();
    var other = item;
    var another = new MySimpleEntity();

    Assert.Same(item, other);
    Assert.NotSame(item, another);
}

Bien, continuaremos luego con más XUnit.NET, todo esto como un empujon para animarlos a probar TDD y en especial esta Testing Framework sumamente útil :)

Saludos!

XUnit.NET para simples mortales

Desde hace tiempo tengo ganas de escribir una serie de posts acerca de TDD y BDD, pero como siento que soy aún un minúsculo saltamontes en el gigantesco mundo de testing, decidí mejor comenzar por algo sumamente básico, qué tal si hablamos de XUnit.Net?

XUnit.Net es una testing framework creada por James Newkirk (ex-desarrolladore de NUnit) y Brad Wilson (ASP.NET developer en Microsoft) la cual agrega excelentes características a nuestra forma de realizar tests.

  • Una sola instancia de test object por método del test
  • No atributos de TearDown o SetUp, de tal manera que se usan los constructores de clase para inicializar el test y Dispose de IDisposable para finalizar el test
  • Sin atributos de ExpectedException, en vez de eso las excepciones son tratadas como un verdadero assert de la forma Assert.Throws
  • Uso extensivo de características de la Framework 2 en adelante (generics, delegados, expresiones lambda)
  • Número pequeño de atributos
  • Totalmente extensible (esta es la parte interesante)

Un típico test en NUnit podría lucir algo así:

[TestFixture]
class TddSample
{
    private string text = string.Empty;
    private DisposableObject objectToDestroy;

    [SetUp]
    public void SetUp()
    {
        objectToDestroy = new ObjectToDestroy();
    }    

    [TearDown]
    public void TearDown()
    {
        objectToDestroy.Dispose();
    }

    [Test]
    public void It_must_be_initialized_with_a_simple_text_in_ctor()
    {
        Assert.IsNotNull(objectToDestroy);
    }

    [Test]
    public void It_should_add_two_numbers()
    {
        var result = 1 + 1;
        Assert.AreEqual(2, result);
    }

    [Test]
    [ExpectedException(typeof(DivideByZeroException))]
    public void It_throws_when_a_number_is_divided_by_zero()
    {
        int i = 0;
        int j = 1;
        var result = j / i;
    }

    [Test]
    [Ignore("I want to break free!")]
    public void It_must_skip_this_test()
    {
        Assert.True(false, "This test would fail");
    }
}

Un equivalente en Xunit.Net podría verse así:

public class SimpleXunitTest : IDisposable
    {
        private readonly string text = string.Empty;
        private readonly DisposableObject objectToDispose;

        public SimpleXunitTest()
        {
            text = "hello world";
            objectToDispose = new DisposableObject();
        }

        [Fact]
        public void It_must_be_initialized_with_a_simple_text_in_ctor()
        {
            Assert.False(string.IsNullOrEmpty(text));
        }

        [Fact]
        public void It_should_add_two_numbers()
        {
            int result = 1 + 1;
            Assert.Equal(2, result);
        }

        [Fact]
        public void It_throws_when_a_number_is_divided_by_zero()
        {
            int i = 0;
            int j = 1;
            Assert.Throws<DivideByZeroException>(() => j/i);
        }

        [Fact(Skip = "I want to break free!")]
        public void It_must_skip_this_test()
        {
            Assert.True(false, "This test would fail");
        }

        public void Dispose()
        {
            objectToDispose.Dispose();
        }
    }

En el sitio del proyecto de XUnit.Net en Codeplex podemos encontrar más equivalencias entre NUnit y XUnit.Net. Una de las verdaderas riquezas de XUnit.Net (a mi criterio muy personal) es la librería adjunta con extensiones conocida como xunit.extensions.dll que contiene atributos especiales que no forman parte a simple vista de la framework de testing, pero nos pueden ayudar mucho en nuestras fixtures, por ejemplo: FreezeClock, o las grandiosas [Theory] con soporte para data inline en nuestros tests ;)

public class SimpleXunitTest
{
    [Theory]
    [InlineData(1, 2, 3)]
    [InlineData(2, 2, 4)]
    [InlineData(4, 5, 9)]
    public void It_should_add_two_numbers_correctly(int a, int b, int c)
    {
        var result = a + b;
        Assert.Equal(c, result);
    }
}

La documentación indica varias formas de incluir la data para las “teorías”, que van desde la inline más simple hasta usar una base de datos y un archivo de Excel.

En cuanto a runners, XUnit soporta TeamCity, MSBuild, R# (mediante proyecto hermano XUnit.Contrib), TestDriven.Net y muchos otros.

Espero mi pequeña intro acerca de XUnit.Net les anime a probarlo. Saludos!