Может ли автоматическое модульное тестирование заменить статическую проверку типов?

StackOverflow https://stackoverflow.com/questions/415434

  •  03-07-2019
  •  | 
  •  

Вопрос

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

Итак, есть ли какая-либо причина использовать язык со статической проверкой типов, если вы также используете модульное тестирование?Был задан несколько похожий вопрос здесь, но я хотел бы остановиться на более подробной информации.Какие конкретные преимущества, если таковые имеются, имеет статическая проверка типов по сравнению с модульными тестами?На ум приходят несколько проблем, таких как оптимизация компилятора и intellisense, но есть ли другие решения для этих проблем?Есть ли другие преимущества / недостатки, о которых я не подумал?

Это было полезно?

Решение

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

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

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

Другие советы

Существует один неизменный факт о качестве программного обеспечения.

  

Если он не может скомпилироваться, он не может быть отправлен

В этом правиле статически типизированные языки победят динамически типизированные языки.

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

  

Чем раньше вы поймаете ошибку, тем дешевле ее исправить

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

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

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

Для любого проекта разумного размера вы не можете учитывать все ситуации только с юнит-тестами.

Таким образом, мой ответ " no " и даже если вам удастся учесть все ситуации, вы тем самым потерпели поражение во всей цели использования динамического языка. р>

Если вы хотите программировать с учетом типов, лучше использовать язык с защитой типов.

Наличие 100% покрытия кода не означает, что вы полностью протестировали свое приложение. Рассмотрим следующий код:

if (qty > 3)
{
    applyShippingDiscount();
}
else
{
    chargeFullAmountForShipping();
}

Я могу получить 100% кодовое покрытие, если введу значения qty = 1 и qty = 4.

А теперь представьте, что мое деловое состояние состояло в том, что " ... для заказов из 3 и более предметов я должен применить скидку к стоимости доставки .. " ;. Тогда мне нужно было бы писать тесты, которые работали на границах. Поэтому я разработал бы тесты, где qty было 2,3 и 4. У меня все еще есть 100% охват, но что более важно, я нашел ошибку в моей логике.

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

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

Люди также склонны забывать значение объявленных типов в качестве документации. Например, если метод Java возвращает List<String>, я сразу же узнаю, что я получаю, не нужно читать документацию, контрольные примеры или даже сам код метода. Аналогично для параметров: если тип объявлен, то я знаю, что ожидает метод.

Значение объявления типа локальных переменных намного ниже, поскольку в хорошо написанном коде область существования переменной должна быть небольшой. Вы все еще можете использовать статическую типизацию: вместо того, чтобы объявлять тип, вы позволяете компилятору выводить его. Такие языки, как Scala или даже C # позволяет вам сделать именно это.

Некоторые стили тестирования приближаются к спецификации, например, QuickCheck или его вариант Scala ScalaCheck генерирует тесты на основе спецификаций, пытаясь угадать важные границы.

Я бы назвал это по-другому - если у вас нет статически типизированного языка, у вас лучше есть очень тщательные модульные тесты, если вы планируете что-то делать " & реальный Quot; с этим кодом.

Тем не менее, статическая типизация (или, скорее, явная типизация) имеет некоторые существенные преимущества по сравнению с модульными тестами, которые заставляют меня предпочитать ее в целом. Он создает гораздо более понятные API и позволяет быстро просматривать & Quot; skeleton & Quot; приложения (т. е. точки входа в каждый модуль или раздел кода) способом, который намного сложнее с языком с динамической типизацией.

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

Нет.

Но это не самый важный вопрос, самый важный вопрос заключается в следующем:имеет ли значение, что это невозможно?

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

Я полагаю, это возможно, если вы будете очень внимательны. Но зачем? Если язык уже проверяет правильность статических типов, нет смысла проверять их (так как вы получаете их бесплатно).

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

Учитывая все преимущества динамических языков с поздним связыванием, я полагаю, что это одно из значений, предлагаемых модульными тестами. Вам по-прежнему нужно кодировать осторожно и намеренно, но это требование № 1 для любого вида кодирования ИМХО. Умение писать понятные и простые тесты помогает доказать ясность и простоту вашего дизайна и вашей реализации. Он также предоставляет полезные подсказки для тех, кто увидит ваш код позже. Но я не думаю, что буду рассчитывать на обнаружение несовпадающих типов. Но на практике я не считаю, что проверка типов в любом случае действительно выявляет много реальных ошибок. Это просто не та ошибка, которую я нахожу в реальном коде, если у вас простой и понятный стиль кодирования.

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

Проверка типов помогает обеспечить соблюдение контрактов между компонентами в системе. Модульное тестирование (как следует из названия) проверяет внутреннюю логику компонентов.

Я думаю, что для единичного блока кода модульное тестирование может сделать ненужной статическую проверку типов. Но в сложной системе автоматизированные тесты не могут проверить все многочисленные способы взаимодействия различных компонентов системы. Для этого использование интерфейсов (которые в некотором смысле являются своего рода & "Контрактом &" Между компонентами) становится полезным инструментом для уменьшения потенциальных ошибок. А интерфейсы требуют проверки типов во время компиляции.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top