Tag Archive for xunit

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!