¿Definir TestMethod's en las clases base de prueba no es compatible con MsTest?

Esta pregunta se refiere a una técnica de prueba de unidad general con una amplia gama potencialmente muy útil de escenarios aplicables. Pero es más fácil de entender con un ejemplo para ilustrar mejor mi pregunta.

Digamos que quiero probar que todos los tipos que anulanEquals() lo hace correctamente Ya queEquals() se define como virtual enSystem.Object, una amplia gama de tipos puede cambiar ese comportamiento. Cada tipo que lo haga deberá someterse a pruebas para asegurarse de que el nuevo comportamiento siga las expectativas implícitas de quien llama con ese método. Especificamente paraEquals(), si anula ese método, la nueva implementación debe asegurarse de que dos objetos iguales también tengan códigos hash iguales, según lo definido porSystem.Object.GetHashCode().

Por lo tanto, para hacer cumplir esto, se necesitarán múltiples clases de prueba y todas probarán la misma consistencia de comportamiento en todos estos tipos.

Para evitar tener que volver a escribir todos los TestMethods necesarios para probar dicho tipo, en su lugar defino una clase de prueba base que se ve a continuación y hago que todas esas clases de prueba hereden el mismo conjunto de pruebas de comportamiento:

/// <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
}

Entonces puedo reutilizar estos TestMethods para cada tipo que anula Equals (). Por ejemplo, esta sería la definición de clase de prueba para probar que elSystem.String implementos de tipoEquals() correctamente.

[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";
    }
}

Esto también se puede ampliar aún más. Por ejemplo, para los tipos que sobrecargan los operadores == y! =, Se puede definir una segunda clase base de prueba abstracta (es decir,EqualsOperatorsFixtureBase<T> : EqualsFixtureBase<T>) que comprueba que la implementación de esos operadores no solo es correcta, sino que también es coherente con las definiciones extendidas deEquals() yGetHashCode().

Puedo hacer esto usando NUnit, pero cuando uso MsTest tengo problemas.

a) Visual Studio 2010 solo descubre elFoo() método de prueba, no los métodos de prueba heredados, por lo que no puede ejecutarlos. Parece que el cargador de prueba de Visual Studio no recorre la jerarquía de herencia de la clase de prueba.

b) Cuando verifico estos tipos en TFS, TFS encuentra el tipo abstracto EqualsFixtureBase y piensa que es una clase de prueba para ejecutar. Pero como no se puede crear, no puede ejecutarlo y etiqueta las pruebas de ese tipo como no concluyentes, lo que falla la ejecución de la prueba y, por lo tanto, la compilación (!).

¿Hay alguna forma de evitar esto, o es una limitación de MsTest y Visual Studio?

Si es así, ¿está arreglando esto en la hoja de ruta para VS / TFS?

Esto sería muy útil, especialmente cuando se prueban tipos de producción que implementan una interfaz, o son parte de una jerarquía de herencia, donde ciertos miembros tienen propiedades semánticas de 'tipo de contrato' o invariantes, si eso tiene sentido.

Básicamente, no tener soporte para esto me impide refactorizar mi código de prueba para eliminar la duplicación.

Gracias

EDITAR: encontréeste enlace a uno de los blogs de MSDN, dice lo siguiente

"En Whidbey, faltaba el soporte para la herencia de la clase de prueba. En Nunit, es totalmente compatible. Esto se rectificará en Orcas".

Eso fue escrito hace más de tres años. ¿Por qué aún no se ha agregado esto? No lo entiendo, hay razones legítimas para tener esto y, en mi opinión, sería un cambio menor. ¿O simplemente no estoy saltando los aros correctos aquí?

Respuestas a la pregunta(4)

Su respuesta a la pregunta