Как я могу гарантировать, что я не нарушу тестовый код при рефакторинге? - PullRequest
7 голосов
/ 20 декабря 2011

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

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

Цикл TDD выглядит примерно так: написать тест, тест не пройден, писать рабочий код до тех пор, пока тест не будет выполнен, рефакторинг кода.Но из того, что я видел, люди реорганизуют производственный код, а не тестовый код.По мере того, как тестовый код затухает, рабочий код устареет, а затем все идет вниз.Поэтому я думаю, что необходимо реорганизовать тестовый код.

Вот проблема: как вы гарантируете, что не нарушаете тестовый код при рефакторинге его?

(ясделал один подход, https://thecomsci.wordpress.com/2011/12/19/double-dabble/,, но я думаю, что мог бы быть лучший путь.)

Очевидно, есть книга, http://www.amazon.com/dp/0131495054,, которую я еще не читал.

Об этом также есть вики-страница, http://c2.com/cgi/wiki?RefactoringTestCode,, для которой нет решения.

Ответы [ 5 ]

2 голосов
/ 28 декабря 2011

Рефакторинг ваших тестов состоит из двух этапов.Проще говоря: сначала вы должны использовать тестируемое приложение, чтобы гарантировать, что тесты пройдут во время рефакторинга.Затем, после того как ваши рефакторизованные тесты станут зелеными, вы должны убедиться, что они не пройдут.Однако для того, чтобы сделать это правильно, нужно выполнить несколько определенных шагов.

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

2 голосов
/ 20 декабря 2011

Я думаю, вы не должны менять свой тестовый код.

Почему?В TDD вы определяете интерфейс для класса.Этот интерфейс содержит методы, которые определены с определенным набором функций. Требования / design .

First: Эти требования не меняютсяпри рефакторинге вашего производственного кода.Рефакторинг означает: изменение / очистка кода без изменения функциональности.
Второе: Тест проверяет определенный набор функциональных возможностей, этот набор остается прежним.

Вывод: Рефакторинг теста и рефакторинг вашего производственного кода - это две разные вещи.

Совет. При написании тестов пишите чистый код.Сделайте небольшие тесты.Которые действительно тестируют одну часть функциональности.

Но «Ваш дизайн меняется из-за непредвиденных изменений требований».Это может привести или не может привести к изменениям в интерфейсе.
При изменении ваших требований ваши тесты должны измениться.Этого не избежать.
Вы должны помнить, что это новый цикл TDD.Сначала проверьте новую функциональность и удалите старые функциональные тесты.Затем внедрите новый дизайн.

Для правильной работы вам необходимы чистые и небольшие тесты.Пример:

MethodOne does: changeA and changeB

Don't put this in 1 unit test, but make a test class with 2 unit tests.
Both execute MethodOne, but they check for other results (changeA, changeB).

When the specification of changeA changes, you only need to rewrite 1 unit method.
When MethodOne gets a new specification changeC: Add a unit test.

В приведенном выше примере ваши тесты будут более гибкими и их будет легче менять.

Резюме:

  • Не выполняйте рефакторинг ваших тестов при рефакторингеваш производственный код.
  • Пишите чистые и гибкие тесты.

Надеется, что это поможет.Удачи вам в этом.

@ disclaimer: Я не хочу ваших денег, если это сделает вас богатым.

1 голос
/ 04 февраля 2015

Примерно за два месяца до того, как ваш вопрос стал одним из моих главных вопросов по рефакторингу. Просто позвольте мне объяснить мой опыт:

  • когда вы хотите провести рефакторинг метода, вы должны покрыть его юнит-тестами (или любыми другими тестами), чтобы убедиться, что вы не нарушаете что-то во время рефакторинга (в моем случае команда знала, что код работает хорошо, потому что они Я использовал его в течение 6 лет, им просто нужно было его улучшить, поэтому все мои модульные тесты прошли первый этап). Итак, на первом этапе у вас есть несколько пройденных модульных тестов, которые охватывают целые сценарии. Если некоторые из модульных тестов не пройдены, сначала нужно решить проблему, чтобы убедиться, что ваш метод работает правильно.

  • после прохождения всех тестов вы провели рефакторинг метода и хотите запустить тест, чтобы убедиться, что все правильно. Какие-либо изменения в тестовых кодах?

  • вы должны написать тесты, которые не зависят от внутренней структуры метода. После рефакторинга вы должны просто изменить небольшую часть кода, и в большинстве случаев никаких изменений не требуется, потому что рефакторинг просто улучшает структуру и не меняет поведение. Если ваш тестовый код нужно было сильно изменить, вы никогда не узнаете, сломали ли вы некоторые вещи в основном коде во время рефакторинга.

  • и самое важное для меня - помнить, что в каждом тесте следует учитывать одно поведение

Надеюсь, я смогу хорошо объяснить.

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

Как вы гарантируете, что вы не нарушите тестовый код при его рефакторинге?

Повторного запуска тестов должно быть достаточно в большинстве случаев.

Естьнекоторые другие стратегии описаны здесь , но они могут быть излишними по сравнению с теми немногими преимуществами, которые вы получаете.

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

Um.

ДЛЯ РЕШЕНИЯ JAVA! Я не знаю, на каком языке ты программируешь!

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

Но это не то, что вы спросили, поэтому давайте попробуем ответить!

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

@SuperTestingFramerworkCapable
public class MyFancyTest {

   @TestEntry
   @Test
   public testXEqualsYAfterConstructors(){
      @TestElement
      //create my object X

      @TestElement
      //create my object Y

      @TheTest
      AssertTrue(X.equals(Y));
   }
}

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

И для каждого члена вашего класса он будет использовать новую таблицу - здесь (единственной) таблицей будет testXEqualsYAfterConstructors И в этой таблице будут столбцы для каждого элемента, помеченного аннотацией @TestElement. И это также будет иметь столбец для @TheTest Я полагаю, что вы просто позвоните в столбцы TestElement1, TestElement2 и т. Д.

И ТОГДА, как только он все это настроит, он просто сохранит имена переменных и строку с аннотацией @TheTest. Таким образом, таблица будет

testXEqualsYAfterConstructors
TestElement1     |  TestElement2     |  TheTest
SomeObjectType X |  SomeObjectType X |  AssertTrue(X.equals(Y));

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

И тогда вы можете продать это решение для этой проблемы, продать свою компанию за 100M и дать мне 20%

ура!

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

@Test
public void equalsIfSameObject()
{
    Person expected = createPerson();
    Person actual = expected;

    check(Person.FEATURE_EQUAL_IF_SAME_OBJECT);
    boolean isEqual = actual.equals(expected);

    assertThat(isEqual).isTrue();
}

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

Опять же, вы можете просто использовать SVN или Perforce и тигель, чтобы сравнить и проверить это!

Кроме того, увидев, что вы заинтересованы в Новой идее, вы захотите прочитать о местных аннотациях: /3801481/kak-ya-mogu-sozdat-protsessor-annotatsii-kotoryi-obrabatyvaet-lokalnuy-peremennuy

Хм, поэтому вам, возможно, понадобится получить этого парня - см. Последний комментарий по ссылке выше - вам также может понадобиться его собственный компилятор java.

@ Отказ от ответственности Если вы создаете новую компанию с кодом, который в значительной степени соответствует вышеприведенному, я оставляю за собой право на 20% компании, если и когда вы стоите более 30 миллионов, в момент моего выбора

...