White-box и Black-box тестирование рекурсивных функций

Я изучил тестирование белого и черного ящиков с точки зрения итеративных функций. Теперь мне нужно выполнить тестирование белого и черного ящиков нескольких рекурсивных функций (в F#). возьмите следующий рекурсивный алгоритм для gcd:

gcd (m, n)
    if  (m % n) = 0 then
         n
    else 
        gcd n ( m % n)

Для теста белого ящика: как я могу охватить различные ветви алгоритма? Наивно можно сказать, что есть две ветви, но когда функция вызывается более одного раза, возможные ветви, очевидно, увеличатся. Должен ли я проводить тестирование с аргументами, которые приводят к разным количествам рекурсивных вызовов, или как точно определить, с какими значениями нужно тестировать?

черный ящик: я получил общее представление о тестировании черного ящика. мы должны посмотреть на возможные значения, с которыми мы могли бы вызвать функцию, не зная ее внутренней работы. В этом случае я просто не уверен, с какими значениями мы можем вызвать его. Одним из способов может быть просто начать с двух значений m и n, для которых gcd = 1, а затем сделать то же самое для значений m и для которых gcd = 2 до некоторого gcd= n для некоторого произвольного числа n. Это то, что нужно делать?

1 ответ

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

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

let rec gcd log m n = 
  let log = (m, n)::log
  if (m % n) = 0 then List.rev log, n
  else gcd log n (m % n)

Теперь для некоторых двух параметров, скажем, 54 и 22, вы можете выполнить вычисления вручную, решить, какими должны быть параметры рекурсивных вызовов, и написать для этого тест:

let log, res = gcd [] 54 22
log |> shouldEqual [ (54, 22); (22, 10); (10, 2) ]

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

let rec gcd m n = 
  if (m % n) = 0 then n
  else gcd n (m % n)

Я бы, вероятно, написал тесты для следующего:

// A random case where one of the numbers is the result
gcd 100 50 |> shouldEqual 50
gcd 50 100 |> shouldEqual 50

// A random case where the only divisor is 1
gcd 13 123 |> shouldEqual 1
gcd 123 13 |> shouldEqual 1

// The following are problematic and I'm not sure what the right behaviour is
gcd 0 0    // This probably should not be allowed    
gcd 10 -5  // This returns -5, but I'm not sure that's what we want

Случайное тестирование. Вы также можете использовать случайное тестирование (которое является формой "черного ящика") для автоматической генерации нескольких тестовых случаев. Есть как минимум два случайных теста, о которых я могу подумать:

  1. Генерация двух случайных чисел, a а также b и проверь что gcd a b = gcd b a, Это тестирование только очень базового свойства, но оно может охватывать довольно много случаев.

  2. Выберите случайное число a и пара простых чисел p1, p2, ..., Затем разделите простые числа на две группы и произведите a*p1*p3*p5 а также a*p2*p4*p6, Напишите тест, который проверяет, что GCD двух чисел a,

Другие вопросы по тегам