Я прежде всего кодер С++, и до сих пор обошлось без написания тестов для всего моего кода. Я решил, что это плохая идея (tm), добавив новые функции, которые тонко сломали старые функции или, в зависимости от того, как вы хотите посмотреть на нее, внедрили некоторые новые "функции".
Но модульное тестирование кажется чрезвычайно хрупким. Вы можете проверить что-то в "идеальных" условиях, но вы не можете увидеть, как ваш код работает, когда материал ломается. Например, это искатель, скажем, он сканирует несколько конкретных сайтов для данных X. Вы просто сохраняете образцы страниц, проверяете их и надеетесь, что сайты никогда не изменятся? Это будет работать отлично, как тесты регрессии, но какие тесты вы могли бы писать, чтобы постоянно проверять эти сайты вживую и сообщать, когда приложение не выполняет эту работу, потому что сайт что-то изменил, что теперь приводит к сбою приложения? Разве вы не хотите, чтобы ваш тестовый пакет отслеживал намерение кода?
Приведенный выше пример немного надуман, и что-то, с чем я не сталкивался (в случае, если вы не догадались). Позвольте мне выбрать то, что у меня есть. Как вы протестируете приложение, выполнит свою работу перед лицом деградировавшего сетевого стека? То есть скажем, что у вас умеренная потеря пакетов по той или иной причине, и у вас есть функция DoSomethingOverTheNetwork()
, которая должна изящно деградировать, когда стек не выполняет, как он предполагал; но не так ли? Разработчик проверяет его лично, намеренно настраивая шлюз, который отбрасывает пакеты для имитации плохой сети, когда он впервые ее пишет. Несколько месяцев спустя кто-то проверяет какой-то код, который изменяет что-то тонко, поэтому деградация не обнаруживается вовремя или приложение даже не распознает деградацию, это никогда не попадает, потому что вы не можете запустить реальный мир тесты, подобные этому, с помощью модульных тестов, можете ли вы?
Далее, как насчет повреждения файлов? Скажем, вы сохраняете список серверов в файле, а контрольная сумма выглядит нормально, но данных на самом деле нет. Вы хотите, чтобы код обрабатывал это, вы пишете код, который, как вы думаете, делает это. Как вы проверяете, что он делает именно это для жизни приложения? Можете ли вы?
Следовательно, хрупкость. Модульные тесты, похоже, проверяют код только в идеальных условиях (и это продвигается, с макетными объектами и т.д.), А не то, с чем они столкнутся в дикой природе. Не поймите меня неправильно, я думаю, что модульные тесты великолепны, но набор тестов, составленный только из них, кажется, является разумным способом ввода тонких ошибок в ваш код, чувствуя чрезмерную уверенность в его надежности.
Как я могу устранить описанные выше ситуации? Если модульные тесты не являются ответом, что такое?
Изменить: я вижу много ответов, которые говорят "просто издевайтесь над этим". Ну, вы не можете "просто издеваться", вот почему: Взяв мой пример деградирующего сетевого стека, предположим, что ваша функция имеет хорошо определенную NetworkInterface, которую мы будем издеваться. Приложение отправляет пакеты по TCP и UDP. Теперь, допустим, эй, пусть имитирует 10% -ную потерю интерфейса, используя макет-объект, и посмотрим, что произойдет. Ваши TCP-соединения увеличивают попытки повторных попыток, а также увеличивают их отдачу, все хорошие практики. Вы решили изменить X% своих UDP-пакетов, чтобы фактически создать TCP-соединение, интерфейс с потерями, мы хотим быть в состоянии гарантировать доставку некоторых пакетов, а другие не должны терять слишком много. Прекрасно работает. Между тем, в реальном мире.., когда вы увеличиваете количество TCP-соединений (или данных через TCP), при достаточно низком соединении, вы в конечном итоге увеличиваете потерю вашего UDP-пакета, так как ваши TCP-соединения будут в конечном итоге -издача их данных все больше и больше и/или сокращение их окна, в результате чего 10% -ная потеря пакетов на самом деле будет больше похожа на потерю пакетов UDP на 90%. Whoopsie.
Нет biggie, пусть это сломается в UDPInterface и TCPInterface. Подождите минуту.. они взаимозависимы, тестирование 10% потери UDP и 10% потери TCP ничем не отличается от вышеизложенного.
Итак, проблема в том, что теперь вы не просто тестируете свой код, вы представляете свои предположения о том, как работает стек TCP операционной системы. И это плохая идея (tm). Гораздо хуже, чем просто избежать всего этого фиаско.
В какой-то момент вам нужно будет создать Mock OS, которая ведет себя точно так же, как ваша реальная ОС, кроме того, можно проверить. Это не похоже на хороший способ продвижения вперед.
Это то, что мы пережили, я уверен, что другие могут добавить свой опыт.
Я надеюсь, что кто-то скажет мне, что я очень неправ, и укажите, почему!
Спасибо!