Подтвердить что ты не робот

Тестирование модулей - как я могу проверить функцию, которая возвращает случайный вывод?

У меня есть функция, которая принимает два параметра и возвращает один или другой 50% времени.

unit test для этого следует определить, что оба параметра могут быть возвращены. К счастью, мне не нужно доказывать, что вероятность для каждого составляет 50%, но мне нужно показать, что оба параметра можно вернуть.

Как написать тестовый пример для этой функции?

4b9b3361

Ответ 1

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

Ответ 2

Вы можете сделать одну из двух вещей:

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

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

Ответ 3

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

int limit = 100;
int i = 0;
while(!firstValueReceived && !secondValueReceived && i < limit) {
   int value = randomFunc();

   if(!firstValueReceived) {
      firstValueReceived = (value == firstValue);
   }

   if(!secondValueReceived) {
      secondValueReceived = (value == secondValue);
   }
   i++;
}

assertTrue(firstValueReceived && secondValueReceived);

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

while(!firstValueReceived && !secondValueReceived) {
   int value = randomFunc();

   if(!firstValueReceived) {
      firstValueReceived = (value == firstValue);
   }

   if(!secondValueReceived) {
      secondValueReceived = (value == secondValue);
   }
}

assertTrue(firstValueReceived && secondValueReceived);

Ответ 4

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

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

Ответ 5

Если решение действительно случайное (или псевдослучайное), то вы можете отделить от своей функции заботу о выборе одного результата из другого. Например, ваша функция может принимать в качестве параметра делегат или другой объект, единственным заданием которого является "переворачивание монетки", но не имеет никакого отношения к двум параметрам или какой-либо логике о них. Затем ваш unit test может предоставить объект для принятия решений, который возвращает результат, который тест хочет проверить.

Ответ 6

Вы проверяете это через разделение и/или injection:

// ** WARNING: Untested code

Оригинал

void funcToTest(String a, String b) {
  int i = new Random().nextInt(2);
  return ((i == 0) ? a : b);
}

Разделительный

void funcToTest(String a, String b) {
  return funcToTest(a, b, (new Random().nextInt(2) == 0));
}
void funcToTest(String a, String b, boolean r) {
  return (r ? a : b);
}

Теперь протестируйте

funcToTest(String a, String b, boolean r).

Вы верите, что если вы проверите выше, то

funcToTest(String a, String b)

будет работать просто.

Инъекционные

interface BoolRandomizer {
  bool getBool();
}
BoolRandomizer BOOL_RANDOMIZER = new BoolRandomizer() {
  public bool getBool() { return (new Random().nextInt(2) == 0); }
}
BoolRandomizer ALWAYS_FALSE_RANDOMIZER = new BoolRandomizer() {
  public bool getBool() { return false; }
}
BoolRandomizer ALWAYS_TRUE_RANDOMIZER = new BoolRandomizer() {
  public bool getBool() { return true; }
}

class ClassUnderTest {
    private final BoolRandomizer br;
    ClassUnderTest() { this(BOOL_RANDOMIZER); }
    ClassUnderTest(BoolRandomizer br) { this.br = br; }
    void funcToTest(String a, String b) {
      return (br.getBool() ? a : b);
    }
}

Теперь протестируйте

new ClassUnderTest(ALWAYS_FALSE_RANDOMIZER).funcToTest()

и

new ClassUnderTest(ALWAYS_TRUE_RANDOMIZER).funcToTest()

Есть, конечно, более сложные /slicker способы сделать это, но это основная идея. Я использовал эти методы для программы колоды карт, чтобы проверить функцию тасования. Другой случай: функция, которая использует текущее время, вызывая системный API gettime(), может быть трудно протестировать, если вы не хотите запускать unit test в очень определенное время суток:-). Тестирование облегчения разделения и впрыска.