Может ли автоматическое модульное тестирование заменить статическую проверку типов? - PullRequest
4 голосов
/ 06 января 2009

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

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

Ответы [ 10 ]

10 голосов
/ 06 января 2009

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

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

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

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

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

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

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

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

6 голосов
/ 06 января 2009

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

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

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

5 голосов
/ 06 января 2009

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

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

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

3 голосов
/ 06 января 2009

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

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

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

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

3 голосов
/ 06 января 2009

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

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

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

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

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

2 голосов
/ 06 января 2009

номер

Но это не самый важный вопрос, самый важный вопрос: важно ли, что он не может?

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

2 голосов
/ 06 января 2009

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

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

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

1 голос
/ 06 января 2009

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

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

0 голосов
/ 13 ноября 2009

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

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

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

0 голосов
/ 06 января 2009

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

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

...