СУХОЙ между константами производственного и тестового кода - PullRequest
10 голосов
/ 14 января 2009

Я обычно стараюсь избегать дублирования и придерживаюсь принципа СУХОЙ. Тем не менее, меня интересует такой случай:

public class Feature {
    final static String FEATURE_LABEL = "blah";

    public void doSomething() { ... }
    ...
}

public class FeatureTest {
    ...
    @Test
    public void doSomethingShouldMakeSomethingHappen() {
         assertEquals(Feature.FEATURE_LABEL, 
             feature.getSomethingHappens().getLabel());
    }

Если требуется, чтобы метка была "бла", а кто-то изменил FEATURE_LABEL на "блеф", тест пройдет, даже если он больше не соответствует требованию Это допустимое место, чтобы нарушить СУХОЙ?

Ответы [ 5 ]

13 голосов
/ 14 января 2009

Да, используйте здесь литерал.

Цитирую себя из вопрос о литералах :

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

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

5 голосов
/ 14 января 2009

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

Не очень хорошая вещь.

Та же идея применима к юнит-тестам. В контексте, подобном приведенному выше, строка, с которой вы тестируете, должна быть абсолютно независимой от того, что находится внутри тестируемого класса. Другими словами, да, вы можете и должен нарушить принцип СУХОГО здесь.

2 голосов
/ 14 января 2009

Другой способ выразить то, что уже сказали другие: если тест никогда не может провалиться, нет смысла его держать. Так что это не имеет смысла:

assertEquals(Feature.FEATURE_LABEL, Feature.FEATURE_LABEL);

Скажем, например, у вас есть ограничение на список. Нет смысла в тестировании, что limit == limit, тест должен пытаться поместить в список больше, чем limit элементов.

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

Тем не менее, для моих собственных тестов пользовательского интерфейса я использую скребки, которые собирают все видимые строки и сравнивают полученную (длинную) строку с содержимым файла. Это очень простой универсальный тест для неожиданных изменений в пользовательском интерфейсе, который лучше всего подходит для пользовательских интерфейсов в HTML (я загружаю HTML и сравниваю его), но тот же шаблон можно применить к любому пользовательскому интерфейсу.

1 голос
/ 14 января 2009

Я бы придерживался ссылки на данный момент.

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

Имеет ли это какой-то смысл?

0 голосов
/ 14 января 2009

Я думаю, что то, что у вас есть, хорошо, и да, это допустимое использование СУХОГО: если это значение закончится в нескольких тестах, вы не хотите менять несколько, если значение меняется. Но вы также должны добавить дополнительный тест, который проверяет значение Feature.FEATURE_LABEL.

Это хорошее место для применения «один раз и только дважды»: если у вас был только один тест, в котором тестировалось значение FEATURE_LABEL, то я бы просто использовал буквальную строку. Только если у вас есть несколько тестов, использующих его, я бы начал использовать ссылку (и добавить тест для значения).

...