Разве определение TestMethod в базовых классах не поддерживается MsTest?

Этот вопрос касается общей методики модульного тестирования с потенциально очень полезным широким спектром применимых сценариев. Но это легче понять на примере, чтобы лучше проиллюстрировать мой вопрос.

Допустим, я хочу проверить, что все типы, которые переопределяютEquals() делает это правильно. посколькуEquals() определяется как виртуальный вSystem.Objectширокий спектр типов может изменить это поведение. Каждый тип, который делает это, должен будет иметь тесты, чтобы удостовериться, что новое поведение соответствует неявным ожиданиям вызывающего этого метода. Специально дляEquals()Если вы переопределите этот метод, новая реализация должна убедиться, что два равных объекта также имеют одинаковые хеш-коды, как определеноSystem.Object.GetHashCode().

Таким образом, для обеспечения этого потребуется несколько тестовых классов, и все они будут проверять одинаковую согласованность поведения для всех этих типов.

Чтобы избежать необходимости повторного ввода всех TestMethods, необходимых для тестирования такого типа, я вместо этого определяю базовый класс тестирования, который выглядит как показано ниже, и чтобы все эти классы тестирования наследовали один и тот же набор тестов поведения:

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

Затем я могу повторно использовать эти TestMethods для каждого типа, переопределяющего Equals (). Например, это будет определение класса теста для проверки того, чтоSystem.String тип реализуетEquals() правильно.

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

Это также может быть расширено. Например, для типов, которые перегружают операторы == и! =, Может быть определен второй базовый класс абстрактного теста (т.е.EqualsOperatorsFixtureBase<T> : EqualsFixtureBase<T>) проверяет, что реализация этих операторов не только правильна, но и соответствует расширенным определениямEquals() а такжеGetHashCode().

Я могу сделать это с помощью NUnit, но при использовании MsTest у меня возникают проблемы.

а) Visual Studio 2010 обнаруживает толькоFoo() Тестовый метод, а не унаследованные тестовые методы, поэтому он не может их запустить. Похоже, что загрузчик тестов Visual Studio не проходит иерархию наследования тестового класса.

б) Когда я проверяю эти типы в TFS, TFS находит абстрактный тип EqualsFixtureBase и думает, что это тестовый класс для запуска. Но так как он не может быть создан, он не может его запустить и помечает тесты этого типа как неокончательные, что не позволяет запустить тест и, следовательно, выполнить сборку (!).

Есть ли способ обойти это, или это ограничение MsTest и Visual Studio?

Если так, исправляет ли это в дорожной карте для VS / TFS ??

Это было бы очень полезно, особенно при тестировании производственных типов, которые реализуют интерфейс или являются частью иерархии наследования, где определенные члены имеют семантические свойства или инварианты «типа контракта» - если это имеет смысл.

По сути, отсутствие поддержки этого препятствует мне в рефакторинге моего тестового кода для устранения дублирования.

Спасибо

РЕДАКТИРОВАТЬ: я нашелэта ссылка на один из блогов MSDN, он говорит следующее

«В Whidbey поддержка наследования тестового класса отсутствовала. В Nunit она полностью поддерживается. Это будет исправлено в Orcas».

Это было написано более трех лет назад. Почему это еще не было добавлено? Я не понимаю, есть законные причины иметь это, и на мой взгляд, это будет незначительное изменение. Или я просто не прыгаю правильные обручи здесь?

Ответы на вопрос(4)

Ваш ответ на вопрос