A definição de TestMethod nas classes base de teste não é suportada pelo MsTest?

Esta pergunta refere-se a uma técnica geral de teste unitário com uma ampla variedade de cenários aplicáveis potencialmente muito úteis. Mas é mais fácil entender com um exemplo para ilustrar melhor minha pergunta.

Digamos que eu queira testar se todos os tipos que substituemEquals() faz isso corretamente. Desde aEquals() é definido como virtual emSystem.Object, uma ampla variedade de tipos pode alterar esse comportamento. Cada tipo que fizer isso precisará ter testes para garantir que o novo comportamento siga as expectativas implícitas de um chamador desse método. Especificamente paraEquals(), se você substituir esse método, a nova implementação deverá garantir que dois objetos iguais também tenham códigos de hash iguais, conforme definido porSystem.Object.GetHashCode().

Assim, para impor isso, serão necessárias várias classes de teste e todas testarão a mesma consistência de comportamento em todos esses tipos.

Para evitar a necessidade de redigitar todos os TestMethods necessários para testar esse tipo, defina uma classe de teste base com a aparência abaixo e faça com que essas classes de teste herdem o mesmo conjunto de testes de comportamento:

/// <summary>
/// Test fixture base class for testing types that overrides Object.Equals()
/// </summary>
/// <typeparam name="T">The production type under test</typeparam>
public abstract class EqualsFixtureBase<T>
{
    #region Equals tests

    protected static void CompareInstances(T inst1, T inst2, bool expectedEquals)
    {
        Assert.AreEqual(expectedEquals, inst1.Equals((T)inst2));
        Assert.AreEqual(expectedEquals, inst1.Equals((object)inst2));
        if (expectedEquals)
        {
            // equal instances MUST have identical hash codes
            // this is a part of the .NET Equals contract
            Assert.AreEqual(inst1.GetHashCode(), inst2.GetHashCode());
        }
        else
        {
            if (inst2 != null)
            {
                Assert.AreNotEqual(inst1.GetHashCode(), inst2.GetHashCode());
            }
        }
    }

    /// <summary>
    /// Creates version 1 instance of the type under test, not 'Equal' to instance 2.
    /// </summary>
    /// <returns>An instance created with properties 1.</returns>
    protected abstract T CreateInstance1();

    /// <summary>
    /// Creates version 2 instance of the type under test, not 'Equal' to instance 1.
    /// </summary>
    /// <returns>An instance created with properties 2.</returns>
    protected abstract T CreateInstance2();

    /// <summary>
    /// Creates an instance equal to the version 1 instance, but not the identical
    /// same object.
    /// </summary>
    /// <returns>An instance created with properties equal to instance 1.</returns>
    protected abstract T CreateInstanceThatEqualsInstance1();

    [TestMethod]
    public void Equals_NullOrDefaultValueTypeInstance()
    {
        T instance = CreateInstance1();
        CompareInstances(instance, default(T), false);
    }

    [TestMethod]
    public void Equals_InstanceOfAnotherType()
    {
        T instance = CreateInstance1();
        Assert.IsFalse(instance.Equals(new object()));
    }

    [TestMethod]
    public void Equals_SameInstance()
    {
        T slot1 = CreateInstance1();
        CompareInstances(slot1, slot1, true);
    }

    [TestMethod]
    public void Equals_EqualInstances()
    {
        T slot1 = CreateInstance1();
        T slot2 = CreateInstanceThatEqualsInstance1();
        CompareInstances(slot1, slot2, true);
        CompareInstances(slot2, slot1, true);
    }

    [TestMethod]
    public void Equals_NonEqualInstances()
    {
        T slot1 = CreateInstance1();
        T slot2 = CreateInstance2();
        CompareInstances(slot1, slot2, false);
        CompareInstances(slot2, slot1, false);
    }

    #endregion Equals tests
}

Posso reutilizar esses TestMethods para cada tipo que substitui Equals (). Por exemplo, essa seria a definição da classe de teste para testar se oSystem.String tipo implementaEquals() corretamente.

[TestClass]
public class ExampleOfAnEqualsTestFixture : EqualsFixtureBase<string>
{
    [TestMethod]
    public void Foo()
    {
        Assert.IsTrue(true);
    }

    protected override string CreateInstance1()
    {
        return "FirstString";
    }

    protected override string CreateInstance2()
    {
        return "SecondString";
    }

    protected override string CreateInstanceThatEqualsInstance1()
    {
        return "FirstString";
    }
}

Isso também pode ser estendido ainda mais. Por exemplo, para tipos que sobrecarregam os operadores == e! =, Uma segunda classe base de teste abstrata pode ser definida (ou seja,EqualsOperatorsFixtureBase<T> : EqualsFixtureBase<T>) que testa se a implementação desses operadores não é apenas correta, mas também consistente com as definições ampliadas deEquals() eGetHashCode().

Eu posso fazer isso usando o NUnit, mas ao usar o MsTest eu tenho problemas.

a) O Visual Studio 2010 descobre apenas oFoo() método de teste, não os métodos de teste herdados, para que não possa executá-los. Parece que o carregador de teste do Visual Studio não percorre a hierarquia de herança da classe de teste.

b) Quando eu faço check-in desses tipos no TFS, o TFS encontra o tipo abstrato EqualsFixtureBase e acha que é uma classe de teste a ser executada. Mas como ele não pode ser criado, não pode ser executado e rotula os testes desse tipo como inconclusivos - o que falha na execução do teste e, portanto, na compilação (!).

Existe uma maneira de contornar isso, ou isso é uma limitação do MsTest e do Visual Studio?

Se sim, está corrigindo isso no roteiro do VS / TFS?

Isso seria muito útil, especialmente ao testar tipos de produção que implementam uma interface ou fazem parte de uma hierarquia de herança, em que certos membros têm propriedades ou invariantes semânticos de 'tipo de contrato' - se isso faz sentido.

Basicamente, não ter suporte para isso me impede de refatorar meu código de teste para remover a duplicação.

obrigado

EDIT: eu encontreiesse link para um dos blogs do MSDN, ele diz o seguinte

"No Whidbey, o suporte à herança da classe de teste estava ausente. No Nunit, ele é totalmente suportado. Isso será corrigido no Orcas".

Isso foi escrito há mais de três anos. Por que isso ainda não foi adicionado? Não entendi, existem razões legítimas para isso e, em minha opinião, seria uma pequena mudança. Ou simplesmente não estou pulando aqui?

questionAnswers(4)

yourAnswerToTheQuestion