Tag Archive for xunit

Provide unit test is not a guarantee of unit testing

In the last years we’ve been hearing a lot about unit testing, so much that now is in the mouth of almost every big or small software company. It’s even so common that many are so brave to say: “If you don’t provide unit tests for your code, then it’s worthless”.

Well, I would be even more brave and say: “If you provide unit tests with your code, even your templates, those test should be worth a penny”.

I found this wonderful piece of code today from a project template:

[TestClass]
public class PackageTest {
    [TestMethod]
    public void CreateInstance() {
        var package = new Walkthrough_01Package();
    }

    [TestMethod]
    public void IsIVsPackage() {
        var package = new Walkthrough_01Package();
        Assert.IsNotNull(package, "The object does not implement IVsPackage");
    }

    [TestMethod]
    public void SetSite() {
        // Create the package
        IVsPackage package = new Walkthrough_01Package();
        Assert.IsNotNull(package, "The object does not implement IVsPackage");

        // Create a basic service provider
        OleServiceProvider serviceProvider = OleServiceProvider.CreateOleServiceProviderWithBasicServices();

        // Site the package
        Assert.AreEqual(0, package.SetSite(serviceProvider), "SetSite did not return S_OK");

        // Unsite the package
        Assert.AreEqual(0, package.SetSite(null), "SetSite(null) did not return S_OK");
    }
}

Ok, let’s just rewrite this test for the sake of just see how would it look like:

public class SamplePackageFacts {
    private readonly IVsPackage _package = new Walkthrough_01Package();

    [Fact]
    public void PackageCanCorrectlySetSiteFromProvider() {
        var site = OleServiceProvider.CreateOleServiceProviderWithBasicServices();
        var answer = _package.SetSite(site);
        Assert.Equal(VSConstants.S_OK, answer);
    }

    [Fact]
    public void PackageCanCorrectlySetNullProvider() {
        var answer = _package.SetSite(null);
        Assert.Equal(VSConstants.S_OK, answer);
    }
}

Can you spot the problem? do you see any value at all in the original three tests methods?

NOTE: I used xUnit just because I like it. It’s not a problem inherited from using the test framework but from the way of look at what is a unit test, you could do exactly the same using MSTest.

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!

XUnit.NET Extensions, TheoryAttribute y DataAttribute

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 ;)

XUnit.NET Extensions, FreezeClock

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);
}

XUnit.NET Extensions, Trace y AutoRollback

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);
}