Есть ли способ защитить имена модульных тестов, следующие шаблону MethodName_Condition_ExpectedBehaviour, от рефакторинга? - PullRequest
6 голосов
/ 27 декабря 2011

Я соблюдаю соглашение об именах

MethodName_Condition_ExpectedBehaviour

когда дело доходит до именования моих юнит-тестов, которые тестируют определенные методы.

например:

[TestMethod]
public void GetCity_TakesParidId_ReturnsParis(){...}

Но когда мне нужно переименовать тестируемый метод, такие инструменты, как ReSharper, не предлагают мне переименовать эти тесты.

Есть ли способ предотвратить появление таких случаев после переименования? Например, изменить настройки ReSharper или следовать более строгому соглашению об именах модульных тестов и т. Д.?

Ответы [ 3 ]

7 голосов
/ 04 января 2012

Недавний шаблон - группировка тестов во внутренние классы по методу, который они тестируют.

Например (без атрибутов теста):

public CityGetterTests 
{
   public class GetCity
   {
      public void TakesParidId_ReturnsParis()
      {
          //...
      }

      // More GetCity tests
   }
}

См. Структурирование модульных тестов изБлог Фила Хаака для подробностей.

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

1 голос
/ 27 декабря 2011

Я также начал с этого преобразования, но в итоге почувствовал, что это не очень хорошо. Теперь я использую имена в стиле BDD, такие как should_return_Paris_for_ParisID.

Это делает мои тесты более читабельными, а также позволяет мне реорганизовывать имена методов, не беспокоясь о моих тестах

0 голосов
/ 30 декабря 2011

Я думаю, что ключ здесь в том, что вы должны тестировать.

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

  1. Для поддержки вашего кода после его написания, так что вы можете выполнять рефакторинг, не опасаясь, что вы что-то сломали

  2. К приведите нас к лучшему способу проектирования компонентов - сначала написание теста действительно заставляет задуматься о том, что необходимо для решения стоящей проблемы.

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

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

Это правда, что имена интерфейсов также будут меняться, но они будут намного более жесткими, чем имена методов. То, что TDD дает нам здесь, - это не просто способ поддержки изменений с помощью тестовой системы, а понимание того, что мы можем пойти по этому пути неправильно!

Возьмем, к примеру, кодовый блок, который вы дали:

[TestMethod]
public void GetCity_TakesParidId_ReturnsParis(){...}
{
    // some test logic here
}

И скажем, мы тестируем метод GetCity () на нашем объекте, CityObtainer - когда я настроил этот объект? Почему я так сделал? Если я понимаю, что GetMatchingCity () - лучшее имя, значит, у вас есть проблема, описанная выше!

Решение, которое я предлагаю, состоит в том, что мы думаем о том, что этот метод действительно означает ранее в процессе, используя интерфейсы:

public interface ICityObtainer
{
    public City GetMatchingCity();
}

При написании этого стиля «вовне» мы вынуждены думать о том, что мы хотим от объекта, намного раньше в процессе, и когда он становится центром, это должно уменьшить его изменчивость. Это не устраняет вашу проблему, но может несколько смягчить ее (и я думаю, что в любом случае это лучший подход).

В идеале мы идем на шаг дальше, и мы даже не пишем код перед началом теста:

[TestMethod]
public void GetCity_TakesParId_ReturnsParis
{
    ICityObtainer cityObtainer = new CityObtainer();
    var result = cityObtainer.GetCity("paris");

    Assert.That(result.Name, Is.EqualTo("paris");
}

Таким образом, я могу увидеть, что я действительно хочу от компонента, прежде чем я даже начну писать - если GetCity () не совсем то, что я хочу, а скорее GetCityByID () , это станет очевидным намного раньше в процессе. Как я уже говорил выше, он не защищен от ошибок, но может немного уменьшить боль в этом конкретном случае.

После того, как вы прошли через это, я чувствую, что если вы меняете название метода, это потому, что вы меняете условия контракта , а это значит, что вы должен вернуться и пересмотреть тест (поскольку возможно, что вы не хотели его менять).

(В качестве краткого дополнения, если мы пишем тест с учетом TDD, то внутри GetCity () происходит что-то, что имеет значительный объем логики. наличие контракта помогает нам отделить намерение от реализации - тест останется действительным независимо от того, что мы изменим за интерфейсом !)

...