Лучшие практики программирования и модульного тестирования - PullRequest
4 голосов
/ 03 октября 2011

Я столкнулся со сценарием, к которому я не слишком уверен, как к нему приблизиться.

Мы пытаемся увеличить охват кода наших модульных тестов до 100%.

I 'мы пытались использовать подход TDD к разработке, написанию тестов, прохождению теста, написанию провального теста, добавлению еще кода для его прохождения и т. д.

При этом я обнаружил, что написал класс, подобныйэто:

public enum IntervalType : int
{
    Shift = 1,
    PaidBreak = 2,
    UnpaidBreak = 3
}


public static class QuarterFactory
{
   public static IQuarter CreateQuarter(IntervalType intervalType)
   {
      switch (intervalType)
      {
           case IntervalType.Shift:
                return new ShiftQuarter();
           default:
                throw new ArgumentException(String.Format("Unable to create a Quarter based on an IntervalType of: {0}", intervalType));
       }
    }
 }

По мере кодирования фабрика расширилась до следующего:

public static class QuarterFactory
{
    public static IQuarter CreateQuarter(IntervalType intervalType)
    {
        switch (intervalType)
        {
            case IntervalType.Shift:
                return new ShiftQuarter();
            case IntervalType.PaidBreak:
                return new PaidBreakQuarter();
            case IntervalType.UnpaidBreak:
                return new UnpaidBreakQuarter();
            default:
                throw new ArgumentException(String.Format("Unable to create a Quarter based on an IntervalType of: {0}", intervalType));
        }
    }
}

Первый вопрос, который я задаю:
Теперь, когдаФабрика выполняет перечисление, удалить ли исключение по умолчанию для покрытия кода или оставить исключение там по умолчанию, если кто-то добавляет новый тип в перечисление и забывает изменить фабрику?

Второй вопрос, который я задаю:
Если я решил удалить исключение и установить тип по умолчанию UnpaidBreakQuarter - имеет ли смысл по умолчаниюIQuarter возвращается в UnpaidBreakQuarter илиЭто подняло бы вопрос: «Почему по умолчанию UnpaidBreakQuarter, есть ли бизнес-правило для этого?».

С уважением,

Джеймс

Ответы [ 4 ]

5 голосов
/ 03 октября 2011

Вы все еще можете получить 100% покрытие кода. Рассмотрим следующую строку, которая прекрасно компилируется:

QuarterFactory.CreateQuarter((IntervalType)0);

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

Итак, вкратце:

  1. Оставьте стандартный модульный тест, который выдает исключение при прохождении что-то неожиданное (например, строка выше)
  2. Не делай этого. Если кто-то не уточнил, что он этого хотел, они не ожидали, что его вернут

Вы даже можете получить исключение, сделав следующее:

QuarterFactory.CreateQuarter(0);
2 голосов
/ 03 октября 2011

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

Ответ навторой вопрос возникает следующим образом :) Кстати, использование значения по умолчанию для указанного значения, потому что «я знаю, что осталось только одно значение - это действительно ужасно, значение по умолчанию предназначалось именно для исключений или непредвиденных случаев, или самое большее для большинстваобщие (то есть: первое нет, второе нет, хорошо, поэтому ЛЮБОЙ другой случай должен быть этим значением).

1 голос
/ 03 октября 2011

Я думаю, что вы должны сохранить значение по умолчанию за счет 100% покрытия кода, если только для этого нет бизнес-правила, и оно не было задокументировано.Если вы решите сохранить его, когда кто-то добавит другое значение в перечисление, будет выдано исключение в качестве «напоминания» для добавления регистра в операторе switch, что, я уверен, является хорошим.

0 голосов
/ 04 октября 2011

Вы знаете, что такого рода комбинация switch / enum обычно является запахом кода, верно? http://c2.com/cgi/wiki?SwitchStatementsSmell

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

Два наиболее распространенных рефакторинга в этом случае - «Заменить код типа на класс» и более конкретный «Заменить код типа на стратегию». Также стоит обратить внимание на «Заменить условное на полиморфизм». http://refactoring.com/catalog/replaceConditionalWithPolymorphism.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...