Как проверить код, который никогда не должен выполняться? - PullRequest
9 голосов
/ 21 августа 2010

Следующий метод должен вызываться только в том случае, если было подтверждено, что имеются недопустимые цифры (путем вызова другого метода). Как я могу протестировать throw -линию в следующем фрагменте? Я знаю, что одним из способов может быть объединение VerifyThereAreInvalidiDigits и этого метода. Я ищу любые другие идеи.

public int FirstInvalidDigitPosition {
    get {
        for (int index = 0; index < this.positions.Count; ++index) {
            if (!this.positions[index].Valid) return index;
        }
        throw new InvalidOperationException("Attempt to get invalid digit position whene there are no invalid digits.");
    }
}

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

Ответы [ 4 ]

22 голосов
/ 21 августа 2010

Если рассматриваемый оператор throw действительно недоступен при любом возможном сценарии, то он должен быть удален и заменен на:

Debug.Fail("This should be unreachable; please find and fix the bug that caused this to be reached.");

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

ОБНОВЛЕНИЕ: согласно комментариям, на самом деле невозможно, чтобы ошибка была нажата, и поэтому код недоступен. Но теперь Debug.Fail также недоступен и не компилируется, потому что компилятор отмечает, что метод, который возвращает значение, имеет достижимую конечную точку.

Первая проблема на самом деле не должна быть проблемой; несомненно, инструмент покрытия кода должен быть настраиваемым, чтобы игнорировать недостижимый код только для отладки. Но обе проблемы можно решить, переписав цикл:

public int FirstInvalidDigitPosition 
{ 
    get 
    { 
        int index = 0;
        while(true) 
        {
            Debug.Assert(index < this.positions.Length, "Attempt to get invalid digit position but there are no invalid digits!");
            if (!this.positions[index].Valid) return index; 
            index++;
        } 
    }
}

Альтернативным подходом было бы реорганизовать код, чтобы у вас не возникла проблема с самого начала:

public int? FirstInvalidDigitPosition { 
    get { 
        for (int index = 0; index < this.positions.Count; ++index) { 
            if (!this.positions[index].Valid) return index; 
        } 
        return null;
    } 
} 

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

4 голосов
/ 21 августа 2010

Иногда необходимо написать небольшие кусочки кода, которые не могут быть выполнены, просто чтобы успокоить компилятор (например, если функция, которая всегда выдает исключение, выходит из приложения и т. Д., Вызывается из функции, которая должна возвращатьзначение, компилятор может настаивать на том, чтобы вызывающая сторона включала оператор «return 0», «Return Nothing» и т. д., который никогда не может быть выполнен. Я не думаю, что нужно проверять такой «код», поскольку это может бытьНевозможно заставить его работать без серьезного нарушения других частей системы.

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

  register = 0
  test register for zero
  if non-zero goto dead
  register = register - 1
  test register for zero
  if non-zero goto okay1
dead:
  shut everything down
  goto dead
okay1:
  register = register + 1
  if non-zero goto dead

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

4 голосов
/ 21 августа 2010

Я не понимаю, почему вы не хотите писать модульный тест, который выполняет «код, который не должен происходить».

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

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

3 голосов
/ 21 августа 2010

Одной из целей тестирования является тестирование того, что должно произойти , и того, что может произойти.

Если у вас есть код, который должен никогда не выполняется, но может при правильных (или неправильных) условиях, вы можете проверить, что исключение происходит в правильных условиях (в модуле модульного тестирования MS), украсив свой метод тестирования с помощью:

[ExpectedException(typeof(InvalidOperationException))]
...