Тестирование итеративного кода с помощью моков — есть ли смысл и как?

Я хочу протестировать алгоритм с помощью макетов. Алгоритм — в текущей реализации — перебирает класс контейнера за несколько проходов и значения set() и get() из него. Цель теста — проверить окончательный результат, хранящийся в контейнере. Окончательное значение зависит от значений, прочитанных и записанных между проходами. например значение любого элемента может измениться многократно, пока алгоритм не завершится, и, скорее всего, его значение в результате итерации n будет зависеть от его значения после итерации n-1.

Мне нравится идея моков, и я хотел бы использовать их в описанном выше сценарии, поскольку это позволило бы мне проверять ошибочное поведение алгоритма, когда оно происходит, а не только после завершения вычислений. Тем не менее, я не уверен, будет ли это на самом деле хорошей идеей, потому что тогда мне придется связать ожидания для фиктивного реального с текущей реализацией (например, «ожидать получить (элемент n) и вернуть x, затем установить ( элемент n, значение x+1), еще один get(n) и return x+1, затем ожидайте set(n, x+2) и т.д.").

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

Теперь мой вопрос: я что-то упустил? Тем не менее, есть ли хороший способ использовать макеты в этом сценарии? или просто нет смысла их здесь использовать? Как другие справляются с этой проблемой?

Последнее замечание: я говорю о тестировании кода С++ и использовании googlemock, если это имеет какое-либо значение для вашего ответа.

ps: я проверил google и статьи здесь (особенно насмешка итеративного поведения - решает только проблему увеличения возврата value), однако я не нашел ничего близкого к моей проблеме.


person jo.tr    schedule 12.09.2011    source источник


Ответы (3)


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

В противном случае использование макета — пустая трата времени. Вы бы использовали издевательскую версию std::vector? я бы не стал; это было бы глупо.

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

person Zan Lynx    schedule 12.09.2011
comment
Насмешка или не насмешка над std::vector на самом деле является хорошим примером. Хотя, как и выше (@Justin), я думаю, что это может быть полезно для проверки каждого шага алгоритма, если что-то пойдет не так, вполне может быть больше работы, чтобы указать такой макет, чем просто пошаговое выполнение кода с ошибками. Так что, я думаю, вы правы, по крайней мере, в большинстве случаев. :) И для общедоступных данных/методов, я думаю, это также верно. Пользователям алгоритма все равно, как вычисляется возвращаемое значение, они просто хотят, чтобы оно было правильным. Спасибо, что изложили свои мысли. - person jo.tr; 13.09.2011

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

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

person Justin ᚅᚔᚈᚄᚒᚔ    schedule 12.09.2011
comment
Я в основном согласен с вами. Однако, прочитав все ответы, я все еще думаю, что было бы неплохо проверить/протестировать отдельные шаги алгоритма. Тем не менее, это, вероятно, не должно быть частью ежедневного тестирования, а скорее чем-то, что может произойти, когда тест начнет давать сбой. С другой стороны, может быть, вы все еще правы насчет пошагового выполнения, потому что код алгоритма уже документирует то, что он должен делать (так же, как макет для проверки отдельных шагов), и вероятность того, что макет в основном просто напоминает исходный код, высока? - person jo.tr; 13.09.2011
comment
На практике это не должно иметь значения, если вы тестируете внутреннюю работу алгоритма, но только запуск тестов, когда ваш выходной тест терпит неудачу, по сути, является определением «отладки» (и в этот момент вы собираетесь быть практическим). во всяком случае с ним). Модульное тестирование — это здорово, но похоже, что вы хотите тестировать только ради тестирования, что не обязательно является лучшим использованием вашего времени. Создайте свой выходной тест, имитируйте столько входных данных, сколько вы можете придумать, и кодируйте, пока алгоритм не выдаст правильный результат для всех входных данных. - person Justin ᚅᚔᚈᚄᚒᚔ; 13.09.2011

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

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

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

person Tom Kerr    schedule 12.09.2011
comment
Я не уверен, что правильно вас понял: вы бы написали тесты с измененным вводом, чтобы проверить вывод, а затем деактивировали их для ежедневных запусков? Разве это не противоречит одной из целей тестирования — убедиться, что реализация по-прежнему ведет себя так, как ожидается, при любых входных данных? Или ваша точка зрения иная? - person jo.tr; 13.09.2011
comment
@jo.tr Модульные тесты должны быть быстрыми, все должно выполняться за секунды. Такие интеграционные тесты, когда они проверяют широкий спектр деталей, могут быть очень длинными. У меня было подобное, на выполнение которого уходило 10 минут, и это просто не круто. - person Tom Kerr; 13.09.2011
comment
Хорошо, да, я согласен. Такие тесты не должны быть частью модульных тестов. Я думал, что мы говорим в целом о быстрых тестах, в основном просто запускаемых несколько раз с разными наборами входных данных. - person jo.tr; 19.09.2011