Я думаю, что ключ здесь в том, что вы должны тестировать.
Вы упомянули TDD в тегах, поэтому я надеюсь, что мы пытаемся придерживаться этого здесь. Согласно этой парадигме, тесты, которые вы пишете, имеют две цели:
Для поддержки вашего кода после его написания, так что вы можете выполнять рефакторинг, не опасаясь, что вы что-то сломали
К приведите нас к лучшему способу проектирования компонентов - сначала написание теста действительно заставляет задуматься о том, что необходимо для решения стоящей проблемы.
Сначала я знаю, что, похоже, этот вопрос касается первого пункта, но на самом деле я думаю, что он касается второго. Проблема в том, что у вас есть конкретные компоненты, которые вы тестируете, а не контракт.
В кодовых терминах это означает, что я думаю, что мы должны тестировать интерфейсы вместо методов класса, потому что в противном случае мы подвергаем наш тест различным проблемам, связанным с тестированием компонентов вместо контрактов - стратегии наследования, конструирование объектов, а тут переименование.
Это правда, что имена интерфейсов также будут меняться, но они будут намного более жесткими, чем имена методов. То, что 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 () происходит что-то, что имеет значительный объем логики. наличие контракта помогает нам отделить намерение от реализации - тест останется действительным независимо от того, что мы изменим за интерфейсом !)