Klávesové zkratky na tomto webu - rozšířené Na obsah stránky

Testy konvencí s xUnit.net

| Moje práce

V každé dobře navržené aplikaci by se měly dodržovat nějaké konvence, které nám umožní psát flexibilní a dopředně kompatibilní kód, který není třeba často měnit. Je vhodné mít tyto konvence někde zdokumentované. Nejlépe pak formou spustitelných tes­tů.

Ukázka z praxe

Zrovna teď řešim messaging za pomocí Rhino.ESB a narazil jsem na potřebu, aby všechny zprávy měly bezparametrický konstruktor a stejně tak i jejich vlastnosti. Jal jsem se psát test a vypadlo mi něco takového:

[Fact]
public void MessagesShouldHaveParameterlessContructor()
{
    var asm = typeof(Message).Assembly;
    var query = from type in asm.GetTypes()
                where type.Namespace == typeof(Message).Namespace
                select type;

    Assert.True(query.All(HasDefaultConstructor));
}

static bool HasDefaultConstructor(Type type)
{
    return type.GetConstructor(Type.EmptyTypes) != null;
}

Super, projdu všechny typy z namespace, kde sídlí zprávy, a zjistím, jestli mají bezparametrický konstruktor. Pokud to všechny zprávy splňují, není problém. Jenže, když jedna tuto konvenci nesplní, jak ji rychle najít? Můžeme přidat nějaký druh výpisu na konzoli, jakou zprávu zrovna testujeme, ale to už porušujeme hned několik doporučení, jak psát RTM testy.

Lepším řešením je využít toho, co nám nabízí framework. Nejde o nic jiného než data driven test. Na to má xUnit.net Theory. Uděláme lehký refactoring a z jednoho ne moc říkajícího testu uděláme serii kokrétních testů, kde hezky uvidíme, které zprávy byly testovány:

public static IEnumerable<object[]> MessageTypes
{
    get
    {
        var asm = typeof(Message).Assembly;
        var query = from type in asm.GetTypes()
                    where type.Namespace == typeof(Message).Namespace
                    select new object[] { type };
        return query;
    }
}

[Theory]
[PropertyData("MessageTypes")]
public void MessagesShouldHaveParameterlessContructor(Type type)
{
    Assert.True(HasDefaultConstructor(type));
}

static bool HasDefaultConstructor(Type type)
{
    return type.GetConstructor(Type.EmptyTypes) != null;
}

Vidíte, ani to moc nebolelo a máme future-proof testy, které nám ohlídají potřeby frameworků a zároveň mají velkou vypovídací hodnotu. Když se podívám na výsledek testů, tak hned vidím, která třída konvenci nedodržuje.

Našli jste v článku chybu? Máte námět na reportáž? Založte mi ticket.