Как провести комплексное тестирование методами - PullRequest
25 голосов
/ 03 ноября 2008

У меня есть метод, который, учитывая угол для севера и угол для подшипника, возвращает значение точки компаса из 8 возможных значений (север, северо-восток, восток и т. Д.). Я хочу создать модульный тест, который обеспечит приличный охват этого метода, предоставляя различные значения для Севера и Пеленга, чтобы обеспечить достаточный охват, чтобы дать мне уверенность в том, что мой метод работает.

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

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

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

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

ПРИМЕЧАНИЕ. Я использую Visual Studio и C #, но считаю, что этот вопрос не зависит от языка.

Ответы [ 10 ]

30 голосов
/ 03 ноября 2008

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

Ваш XML-файл должен содержать только подмножество входных данных, которые вы описали. Ваши тесты должны убедиться, что вы можете работать с экстремальными диапазонами входной области (-360, 360), несколькими точками данных, находящимися непосредственно в конце диапазона, и несколькими точками данных в середине. Ваши тесты также должны проверять, что ваш код корректно завершается с ошибкой, когда заданные значения выходят за пределы входного диапазона (например, -361 и +361).

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

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

5 голосов
/ 03 ноября 2008

Я предпочитаю делать следующее.

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

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

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

    def testCase215n( self ):
        self.fixture.setCourse( 215 )
        self.fixture.setBearing( 45 )
        self.fixture.calculate()
        self.assertEquals( "N", self.fixture.compass() )
    

[Это Python, та же идея применима и к C #.]

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

Для этого я использую небольшую программу на Python с xlrd и генератором шаблонов Mako. Вы можете сделать что-то подобное с продуктами C #.

5 голосов
/ 03 ноября 2008

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

4 голосов
/ 03 ноября 2008

Если вы можете думать о совершенно другой реализации вашего метода с совершенно разными местами для скрытия ошибок, вы можете проверить это. Я часто делаю такие вещи, когда получаю эффективную, но сложную реализацию чего-то, что может быть реализовано гораздо проще, но неэффективно. Например, если вы пишете реализацию хеш-таблицы, я мог бы реализовать ассоциативный массив на основе линейного поиска, чтобы проверить его, а затем протестировать, используя множество случайно сгенерированных входных данных. Линейный поиск АА очень сложно испортить и еще сложнее испортить, так что он ошибочен в том же способе, что и в хеш-таблице. Поэтому, если хеш-таблица имеет такое же наблюдаемое поведение, как и линейный поиск AA, я был бы уверен, что это правильно.

Другими примерами могут быть написание пузырьковой сортировки для проверки сортировки кучи или использование известной функции рабочей сортировки для поиска медиан и сравнение ее с результатами реализации алгоритма поиска медианы O (N).

3 голосов
/ 03 ноября 2008

Я считаю, что ваше решение в порядке, несмотря на использование файла XML (я бы использовал простой текстовый файл). Но более используемой тактикой является просто тестирование предельных ситуаций, например, использование в вашем случае значения входа -360, 360, -361, 361 и 0.

1 голос
/ 03 ноября 2008

Не уверен, насколько сложен ваш код, если он принимает целое число и делит его на 8 или 16 направлений на компасе, возможно, это несколько строк кода, да?

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

В этом конкретном случае я бы записывал каждое число в порядке от -360 до +360 и печатал число и результат (в текстовый файл в формате, который можно скомпилировать в другую программу в виде файла заголовка). Визуально проверьте, что направление изменяется при желаемом входе. Это должно быть легко визуально осмотреть и проверить. Теперь у вас есть таблица входов и действительных выходов. Затем предложите программе случайным образом выбрать один из допустимых входных данных, введите его в тестируемый код и убедитесь, что правильный ответ получен. Сделайте несколько сотен этих случайных тестов. В какой-то момент вам нужно проверить, что числа меньше -360 или больше +360 обрабатываются в соответствии с вашими требованиями, я полагаю, отсечение или модулирование.

1 голос
/ 03 ноября 2008

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

0 голосов
/ 06 ноября 2008

Psuedocode:

array colors = { red, orange, yellow, green, blue, brown, black, white }
for north = -360 to 361
    for bearing = -361 to 361
        theColor = colors[dirFunction(north, bearing)] // dirFunction is the one being tested
        setColor (theColor)
        drawLine (centerX, centerY,
                  centerX + (cos(north + bearing) * radius),
                  centerY + (sin(north + bearing) * radius))
        Verify Resulting Circle against rotated reference diagram.

Когда Север = 0, вы получите 8-цветную круговую диаграмму. Поскольку север изменяется на + или -, круговая диаграмма будет выглядеть одинаково, но повернута на столько градусов. Тестовая проверка - это простой способ убедиться, что (а) изображение представляет собой правильно повернутую круговую диаграмму и (б) в оранжевой области нет зеленых пятен и т. Д.

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

0 голосов
/ 03 ноября 2008

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

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

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

0 голосов
/ 03 ноября 2008

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

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

Другим способом является тестирование на уровне филиала или предикатное тестирование покрытия. покрытие кода не защищает от ошибок, но не покрывает весь ваш код, кажется безответственным.

...