MSTest, MyClassInitialize и переменные экземпляра

Интересно, что лучше всего для инициализации переменных экземпляра в тестовом классе в MSTest. Скажем, у меня есть тестовый класс, где есть много накладных расходов, чтобы насмехаться и настраивать поддерживающие объекты. Я хочу сделать это один раз, вместо того, чтобы повторять один и тот же код в каждом тесте. Моя мысль заключалась в том, чтобы использовать метод MyClassInitialize для инициализации некоторых глобальных переменных экземпляра, к которым имели доступ все тесты. Таким образом, я инициализирую глобальные переменные экземпляра один раз, и они просто используются каждым тестом по мере их запуска.

К сожалению, метод MyClassInitialize является статическим, поэтому не может инициализировать глобальные переменные экземпляра. Я думал о том, чтобы сделать глобальные переменные экземпляра статическими, но не кажется правильным решением. Затем я подумал о том, чтобы просто поставить код инициализации в конструктор самого тестового класса, но что-то внутри меня продолжает говорить, что MyClassInitialize - это то, что я должен использовать. Другая мысль заключалась бы в использовании MyTestInitialize, поскольку этот метод не является статическим, но это будет создавать объект снова и снова с каждым тестом. Это подходит?

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

[TestClass()]
public class ProgramTest
{
    // this object requires extensive setup so would like to just do it once
    private SomeObjectThatIsUsedByAllTestsAndNeedsInitialization myObject;
    private TestContext testContextInstance;

    [ClassInitialize()]
    public static void MyClassInitialize(TestContext testContext)
    {
        // initializing SomeObjectThatIsUsedByAllTestsAndNeedsInitialization clearly will
        // not work here because this method is static.
    }

    [TestMethod()]
    public void Test1()
    {
        // use SomeObjectThatIsUsedByAllTestsAndNeedsInitialization here
    }

    [TestMethod()]
    public void Test2()
    {
        // use SomeObjectThatIsUsedByAllTestsAndNeedsInitialization here
    }

    [TestMethod()]
    public void Test3()
    {
        // use SomeObjectThatIsUsedByAllTestsAndNeedsInitialization here
    }
}

Ответ 1

По возможности используйте [TestInitialize] и [TestCleanup]. A unit test должен быть быстрым и изолированным, поэтому самый чистый способ - инициализировать и очищать для каждого теста. Это гарантирует, что результаты теста не будут влиять на другой тест. Когда инициализация теста длится долго, вы, вероятно, не пропустили unit test, а тест интеграции.

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

Ответ 2

В чем проблема со статикой?

Если ваши ObjectThatIsUsedByAllTests действительно могут быть действительно 100% разделены между всеми вашими тестами, сделайте его статическим и используйте ClassInitialize - для чего он нужен.

Если это не так, вам нужно инициализировать его на каждый тест, для которого предназначен TestInitialize.

Ответ 3

Вы можете использовать ленивую инициализацию переменной экземпляра в каком-то другом классе. Не забывайте, что MSTest создаст новый экземпляр тестового класса для каждого метода тестирования, который он запускает. Поэтому любые переменные в этом классе, которые вы хотите сохранить в тестовых методах, должны быть более статичными.