2010-08-15 2 views
3

Рассмотрим следующий код (из условия, что говорит, что 3 является особенным по некоторым причинам):Модульное тестирование конкретных значений

bool IsSpecial(int value) 
    if (value == 3) 
     return true 
    else 
     return false 

Я бы модульное тестирование это с парой функций - одна называется TEST (3IsSpecial) который утверждает, что при передаче 3 функция возвращает true и другую, которая передает некоторое случайное значение, отличное от 3, и утверждает, что функция возвращает false.

Когда требование меняется и говорит, что теперь оно становится 3 и 20 являются специальными, я бы написал еще один тест, который проверяет, что при вызове с 20 эта функция также возвращает true. Этот тест потерпит неудачу, и тогда я перейду и обновить условие if в функции.

Теперь, если в моей команде есть люди, которые не верят в модульное тестирование, и они вносят это изменение. Они будут напрямую перемещаться и изменять код, так как мой второй единичный тест может не тестироваться на 20 (это может быть случайный выбор int или какой-то другой int hardcoded). Теперь мои тесты не синхронизируются с кодом. Как я могу убедиться, что при изменении кода какой-либо модульный тест или другой сбой?

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

ответ

2

Это хороший вопрос. Как вы заметили, выбор из Not3IsNotSpecial случайным значением не-3 будет традиционным подходом. Это не изменило бы определение «специального».

В среде .NET вы можете использовать возможность ввода новых кодов для записи тестового предиката (postcondition) непосредственно в методе. Статический анализатор поймает дефект, который вы предложили. Например:

Contract.Ensures(value != 3 && Contract.Result<Boolean>() == false); 

Я думаю, что любой, кто является поклонником TDD, сейчас экспериментирует с контрактами, чтобы увидеть шаблоны использования. Идея о том, что у вас есть инструменты для доказательства правильности, очень сильна. Вы можете даже указать эти предикаты для интерфейса.

Единственный подход к тестированию, который я видел, касался этого вопроса: Model Based Testing. Идея похожа на подход контрактов. Вы настроили условие Not3IsNotSpecial абстрактно (например, IsSpecial(x => x != 3) == false)), и пусть среда выполнения модели генерирует конкретные тесты. Я не уверен, но я думаю, что эти среды также используют статический анализ. В любом случае, вы позволяете среде выполнения модели работать непрерывно против вашего SUT. Я никогда не использовал такую ​​среду, но концепция интересна.

1

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

Вот что приходит ко мне с головы. У многих репозиториев есть крючки, которые позволяют вам запускать некоторый процесс при каждой регистрации, например, при запуске модульных тестов. Можно установить критерий, что только что проверенный код должен достигнуть некоторого порога покрытия кода при модульных тестах. Если коммит не соответствует определенным метрикам, он отклоняется.

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

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

1

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

Теперь вы можете проверить здесь, что этот тест должен завершиться неудачно, если значение не существует в перечислении. И для класса enum напишите тест, чтобы проверить возможные значения. Если добавляется новое возможное значение, ваш тест должен завершиться неудачно.

Так что ваш метод будет:

bool IsSpecial(int value) 
    if (SpecialValues.has(value)) 
     return true 
    else 
     return false 

и ваши SpecialValues ​​будет перечисление как:

enum SpecialValues { 

Три (3), Twenty (20)

public int value; 
} 

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

+0

Если я нахожусь на C++, тогда нет возможности делать перечисления SpecialValues ​​и проверять SpecialValues.has (3) или SpecialValues.has (20). Это становится проблемой, не так ли? – obelix

+0

Я не уверен в этом, но вы можете перебирать значения в C++. Если да, то вы можете реализовать функции внутри своего IsSpecial. –

0

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

  • 20 может иметь было некоторым допустимым условием для проверки на основе знания бизнес-домена. Написание тестов в стиле BDD, основанных на знании бизнес-проблемы, возможно, помогло вам явно поймать его.

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