Как использовать комбинации наборов в качестве тестовых данных

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

(inf,0,-1), (5,10,1000), (10,5,5), (0,-1,5), (1000,inf,inf),
...

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

Ответ 1

Абсолютно, особенно имея дело с множеством этих перестановок/комбинаций, я определенно вижу, что первый проход будет проблемой.

Интересная реализация в python, хотя я написал хороший в C и Ocaml на основе "Алгоритм 515" (см. ниже). Он написал его в Фортране, поскольку он был распространен тогда для всех документов "Алгоритм XX", ну, эта сборка или c. Мне пришлось переписать его и сделать небольшие улучшения для работы с массивами, а не диапазонами чисел. Этот случай делает произвольный доступ, я все еще работаю над получением некоторых хороших реализаций из тех, что упомянуты в четвертом томе Кнута. Я объясню, как это работает для читателя. Хотя, если кому-то интересно, я бы не стал возражать против чего-то.

/** [combination c n p x]
 * get the [x]th lexicographically ordered set of [p] elements in [n]
 * output is in [c], and should be sizeof(int)*[p] */
void combination(int* c,int n,int p, int x){
    int i,r,k = 0;
    for(i=0;i<p-1;i++){
        c[i] = (i != 0) ? c[i-1] : 0;
        do {
            c[i]++;
            r = choose(n-c[i],p-(i+1));
            k = k + r;
        } while(k < x);
        k = k - r;
    }
    c[p-1] = c[p-2] + x - k;
}

~ "Алгоритм 515: Генерация вектора из лексикографического указателя"; Пряжки, Б. П. и Либанон, М. ACM Transactions on Mathematical Software, Vol. 3, № 2, июнь 1977 г.

Ответ 2

Интересный вопрос!

Я бы сделал это, выбрав комбинации, например, в python. Самая сложная часть - это, вероятно, проверка первого прохода, т.е. if f(1,2,3) returns true, это правильный результат? После того, как вы подтвердили это, это будет хорошей основой для тестирования регрессии.

Наверное, неплохо сделать набор тестовых случаев, которые, как вы знаете, будут истинными (например, 3,4,5 для этого случая треугольника), а набор тестовых случаев, которые, как вы знаете, будут ложными (например, 0,1, инф). Затем вы можете более легко проверить правильность тестов.

# xpermutations from http://code.activestate.com/recipes/190465
from xpermutations import *

lengths=[-1,0,1,5,10,0,1000,'inf']
for c in xselections(lengths,3):        # or xuniqueselections
    print c
(-1,-1,-1);
(-1,-1,0);
(-1,-1,1);
(-1,-1,5);
(-1,-1,10);
(-1,-1,0);
(-1,-1,1000);
(-1,-1,inf);
(-1,0,-1);
(-1,0,0);
...

Ответ 3

С новым Python 2.6 у вас есть стандартное решение с модулем itertools, который возвращает декартово произведение итераций:

import itertools

print list(itertools.product([1,2,3], [4,5,6]))
   [(1, 4), (1, 5), (1, 6),
   (2, 4), (2, 5), (2, 6),
   (3, 4), (3, 5), (3, 6)]

Вы можете предоставить аргумент "repeat" для выполнения продукта с помощью итерации и самого себя:

print list(itertools.product([1,2], repeat=3))
[(1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2),
(2, 1, 1), (2, 1, 2), (2, 2, 1), (2, 2, 2)]

Вы также можете настроить что-то с комбинациями:

print list(itertools.combinations('123', 2))
[('1', '2'), ('1', '3'), ('2', '3')]

И если порядок имеет значение, есть перестановки:

print list(itertools.permutations([1,2,3,4], 2))
[(1, 2), (1, 3), (1, 4),
   (2, 1), (2, 3), (2, 4),
   (3, 1), (3, 2), (3, 4),
   (4, 1), (4, 2), (4, 3)]

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

Просто помните, что вы можете преобразовать кортеж или список в набор и наоборот, используя list(), tuple() и set().

Ответ 4

Я думаю, вы можете сделать это с помощью Row Test Attribute (доступно в MbUnit и более поздних версиях NUnit), где вы можете указать несколько наборов для заполнения одного unit test.

Ответ 5

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

С точки зрения обычного QA вы хотели бы определить различные классификации входов. Произведите набор входных значений для каждой классификации и определите соответствующие результаты.

Здесь образец классов входных значений

  • действительные треугольники с небольшими номерами, такими как (1 миллиард, 2 миллиарда, 2 миллиарда)
  • действительные треугольники с большими числами, такими как (0,000001, 0,00002, 0,00003)
  • действительные тупые треугольники, которые "почти", такие как (10, 10, 19.9999).
  • действительные острые треугольники, которые "почти" плоские, такие как (10, 10, 0000001)
  • неверные треугольники с хотя бы одним отрицательным значением
  • неверные треугольники, где сумма двух сторон равна третьей
  • неверные треугольники, где сумма двух сторон больше третьей
  • входные значения, которые не являются числовыми

...

Как только вы удовлетворены списком входных классификаций для этой функции, вы можете создать фактические данные теста. Вероятно, было бы полезно проверить все перестановки каждого элемента. (например, (2,3,4), (2,4,3), (3,2,4), (3,4,2), (4,2,3), (4,3,2)) Как правило, вы обнаружите, что есть некоторые классификации, которые вы пропустили (например, понятие inf как входной параметр).

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

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