Модульное тестирование побочного эффекта кода

10

Я начинаю писать код на C ++ для запуска робота, и я не знаю, как включить модульное тестирование, если действительно смогу. Мне предоставили библиотеку, которая позволяет создавать «команды» для робота, которые автоматически планируются и выполняются. Механизм создания этих команд является подкласс команды базового класса они предоставляют, и осуществлять виртуальную void Initialize(), void Execute()и void End()методу. Эти функции выполняются исключительно из-за их побочных эффектов, которые влияют на работу робота (запуск двигателей, выдвижение поршней и т. Д.). Из-за этого я нигде не вижу возможности прикрепить модульные тесты к коду, если не считать насмешки над всей библиотекой, чтобы я мог проверять виртуальные состояния робота до и после. Есть ли способ модульного тестирования, который не слишком обременителен?

редактировать

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

Уилл Кункель
источник
Я предполагаю, что вы можете отменить любое действие, которое заставляет своего робота делать, верно? Разве вы не можете отменить действия вашего теста?
Нил
1
Жаль, что библиотека не использовала композицию вместо наследования, потому что в этом случае вы могли бы просто посмеяться над классом команд.
Роберт Харви
@ Нил, я не совсем уверен, что ты спрашиваешь. Вы можете перефразировать свой вопрос?
Уилл Кункель

Ответы:

7

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

После этого я создал бы класс RobotControlImpl, который реализует этот интерфейс против реальной библиотеки роботов.

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

Таким образом, вы можете смоделировать RobotControl, передать макет любой команде и убедиться, что он вызвал правильные методы интерфейса.

В prod вы передадите реальный смысл RobotControl командам, которые вы реализовали.

Я не уверен, что это то, что вы имели в виду и считаете громоздким?

Редактировать: О, и если вы ожидаете, что команды будут спать, чтобы ждать завершения (кошмар, но иногда это то, что у вас есть), я бы потребовал, чтобы команды вызывали метод сна в RobotControl. Таким образом, вы можете отключить спящие режимы во время теста и просто проверить, что команда пытается перейти в спящий режим.

Александр Торстлинг
источник
2
+1. Не нравится интерфейс? Сделай свой собственный.
Нил
Похоже, вы предлагаете мне издеваться над всей библиотекой. Почти все функции, которые будут вызывать команды, являются внутренними для библиотеки.
Уилл Кункель
0

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

Это требует отдельной «сборки модульного теста» вашего кода.

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

Затем у вас есть команды, которые вы можете добавить в свою собственную среду тестирования, которая вызывает те же методы, что и библиотека роботов.

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

Изменение имени базового класса может быть сделано с помощью #define или, возможно, предпочтительным, typedef.

JDV-Ян де Ваан
источник