Подтвердить что ты не робот

Как организовать модульные тесты и не делать рефакторинг кошмаром?

Мой текущий способ организации модульных тестов сводится к следующему:

  • Каждый проект имеет свой собственный выделенный проект с модульными тестами. Для проекта BusinessLayer существует тестовый проект BusinessLayer.UnitTests.
  • Для каждого класса, который я хочу протестировать, в тестовом проекте есть отдельный тестовый класс, размещенный в точно такой же структуре папок и в точно таком же пространстве имен, что и тестируемый класс. Для класса CustomerRepository из пространства имен BusinessLayer.Repositories существует тестовый класс CustomerRepositoryTests в пространстве имен BusinessLayerUnitTests.Repositories.

Методы внутри каждого тестового класса следуют простым соглашениям об именах MethodName_Condition_ExpectedOutcome. Таким образом, класс CustomerRepositoryTests, содержащий тесты для класса CustomerRepository с определенным методом Get, выглядит следующим образом:

[TestFixture]
public class CustomerRepositoryTests
{
    [Test]
    public void Get_WhenX_ThenRecordIsReturned()
    {
        // ...
    }

    [Test]
    public void Get_WhenY_ThenExceptionIsThrown()
    {
        // ...
    }
}

Этот подход мне очень понравился, потому что он делает локальные тесты для некоторого фрагмента кода очень простыми. На противоположном сайте он делает рефакторинг кода действительно более сложным, тогда он должен быть:

  • Когда я решаю разделить один проект на несколько меньших, мне также нужно разделить мой тестовый проект.
  • Когда я хочу изменить пространство имен класса, я должен помнить об изменении пространства имен (и структуры папок) тестового класса.
  • Когда я меняю имя метода, мне нужно пройти все тесты и изменить имя там. Конечно, я могу использовать Search and Replace, но это не очень надежно. В конце концов, мне все равно нужно проверить изменения вручную.

Есть ли какой-нибудь умный способ организации модульных тестов, которые все же позволили бы быстро найти тесты для конкретного кода и в то же время дать больше возможностей для рефакторинга?

В качестве альтернативы есть некоторые, возможно, расширение Visual Studio, которые позволили бы мне как-то сказать, что "эй, эти тесты для этого метода, поэтому, когда имя метода изменяется, будьте так добры и измените тесты также"? Честно говоря, я серьезно подумываю написать что-то подобное себе.

4b9b3361

Ответ 1

После многого работая с испытаниями, я понял, что (по крайней мере для меня) все эти ограничения приносят много проблем в долгосрочной перспективе, а не в хорошие вещи. Поэтому вместо того, чтобы использовать "Имена" и соглашения, чтобы определить это, мы начали использовать код. Каждый проект и каждый класс могут иметь любое количество тестовых проектов и тестовых классов. Весь тестовый код организован на основе того, что тестируется с точки зрения функциональности (или того, какое требование оно реализует, или какой ошибки он воспроизводит и т.д.). Затем для поиска тестов для фрагмента кода мы делаем следующее:

[TestFixture]
public class MyFunctionalityTests
{
    public IEnumerable<Type> TestedClasses()
    {
        // We can find the tests for a class, because the test cases references in some special method.
        return new []{typeof(SomeTestedType), typeof(OtherTestedType)};
    }

    [Test]
    public void TestRequirement23423432()
    {
        // ... test code.
        this.TestingMethod(someObject.methodBeingTested); //We do something similar for methods if we want to track which methods are being tested (we usually don't)
        // ... 
    }
}

Мы можем использовать такие инструменты, как resharper "usages", чтобы найти тестовые примеры и т.д. И когда этого недостаточно, мы делаем магию с помощью отражения и LINQ, загружая все тестовые классы и запуская что-то вроде allTestClasses.where(testClass => testClass.TestedClasses().FindSomeTestClasses()); Вы также можете использовать TearDown для сбора информации о том, какие методы тестируются каждым методом/классом и сделать то же самое.

Ответ 2

Один из способов сохранить синхронизацию классов и тестовых объектов при перемещении кода:

  • Переместить код в одноименное временное пространство имен
  • Поиск ссылок на это пространство имен в тестах для идентификации тестов, которые необходимо переместить.
  • Переместите тесты в нужное новое место.
  • Как только все ссылки на временное пространство имен из тестов находятся в нужном месте, переместите исходный код в целевую цель.

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

Ответ 3

Что касается VS-расширений, которые связывают код с тестами, взгляните на Visual Studio Test Impact. Он запускает тесты под профилировщиком и создает компактную базу данных, которая отображает точки последовательности IL для модульных тестов. Другими словами, при изменении кода Visual Studio знает, какие тесты нужно запускать.

Ответ 4

Один проект unit test для каждого проекта - это путь. Мы попробовали проект mega unit test, но это увеличило время компиляции.

Чтобы помочь вам в рефакторе использовать такой продукт, как resharper или code бросаться.

Ответ 5

Есть ли какой-то умный способ организации модульных тестов, которые все равно будут позвольте мне быстро найти тесты для определенного кода.

У Resharper есть несколько хороших коротких сокращений, которые позволяют вам искать файл или код

Как вы сказали для класса CustomerRepository, это тест CustomerRepositoryTests

Ярлык R # показывает поле ввода для того, что вы найдете в вашем случае, вы можете просто ввести CRT, и он покажет вам, что все файлы, начинающиеся с имени, сначала имеют значение Capital C, затем R, а затем T

Это также позволяет выполнять поиск по диким картам, например, CR * покажет вам список файлов CustomerRepository и CustomerRepositoryTests