Вы можете найти бесконечный список блогов, статей и сайтов, рекламирующих преимущества модульного тестирования вашего исходного кода. Почти гарантировано, что разработчики, которые программировали компиляторы для Java, C ++, C # и других типизированных языков, использовали модульное тестирование для проверки своей работы.
Так почему же, несмотря на свою популярность, тестирование отсутствует в синтаксисе этих языков?
Microsoft представила LINQ для C # , так почему же они не могли добавить тестирование?
Я не пытаюсь предсказать, какими будут эти языковые изменения, но чтобы прояснить, почему они отсутствуют с самого начала.
В качестве примера: мы знаем, что вы можете написать for
цикл без синтаксиса for
оператора. Вы можете использовать while
или if
/ goto
заявления. Кто-то решил, что for
заявление было более эффективным, и ввел его в язык.
Почему тестирование не следовало той же эволюции языков программирования?
источник
Ответы:
Как и во многих других случаях, модульное тестирование лучше всего поддерживается на уровне библиотеки, а не на уровне языка. В частности, в C # имеется множество библиотек модульного тестирования, а также вещи, которые являются родными для .NET Framework, например
Microsoft.VisualStudio.TestTools.UnitTesting
.Каждая библиотека модульного тестирования имеет несколько разные принципы и синтаксис тестирования. При прочих равных условиях, лучший выбор лучше, чем меньше. Если бы модульное тестирование было запрограммировано на язык, вы либо были бы привязаны к выбору дизайнера языка, либо использовали бы ... библиотеку, и вообще отказались бы от возможностей языкового тестирования.
Примеры
Nunit - универсальная идиоматически разработанная инфраструктура для модульного тестирования, которая в полной мере использует возможности языка C #.
Moq - Mocking Framework, который в полной мере использует лямбда-выражения и деревья выражений без метафоры записи / воспроизведения.
Есть много других вариантов. Такие библиотеки, как Microsoft Fakes, могут создавать макеты "shims ...", которые не требуют написания ваших классов с использованием интерфейсов или виртуальных методов.
Linq не является языковой функцией (несмотря на название)
Linq - это библиотека. Мы получили много новых функций в самом языке C # бесплатно, таких как лямбда-выражения и методы расширения, но фактическая реализация Linq находится в .NET Framework.
Есть некоторый синтаксический сахар, который был добавлен в C #, чтобы сделать операторы linq более чистыми, но этот сахар не требуется для использования linq.
источник
var
ключевым словом :)Есть много причин. Эрик Липперт много раз заявлял, что причина
feature X
не в C #, а в том, что его нет в бюджете. Языковые дизайнеры не имеют бесконечного количества времени и денег для реализации, и каждая новая функция связана с затратами на обслуживание. Сохранение языка как можно меньшего размера не просто легче для разработчиков языка, но и для любого, кто пишет альтернативные реализации и инструменты (например, IDE). Кроме того, когда что-то реализовано с точки зрения языка, а не его части, вы получаете Портативность бесплатно. Если модульное тестирование реализуется как библиотека, вам нужно написать ее только один раз, и она будет работать в любой соответствующей реализации языка.Стоит отметить, что D имеет поддержку на уровне синтаксиса для модульного тестирования . Я не знаю, почему они решили добавить это, но стоит отметить, что D предназначен для «языка системного программирования высокого уровня». Дизайнеры хотели, чтобы он был жизнеспособным для небезопасного низкоуровневого кода, для которого традиционно используется C ++, а ошибка в небезопасном коде невероятно дорогая - неопределенное поведение. Поэтому я полагаю, что им было бы целесообразно приложить дополнительные усилия ко всему, что поможет вам проверить, работает ли какой-нибудь небезопасный код. Например, вы можете принудить, чтобы только определенные доверенные модули могли выполнять небезопасные операции, такие как непроверенный доступ к массиву или арифметика указателя.
Быстрая разработка также была для них приоритетом, настолько, что они поставили перед собой цель разработки, чтобы D-код компилировался достаточно быстро, чтобы его можно было использовать в качестве языка сценариев. Выпекание юнит-тестов прямо на языке, так что вы можете запустить свои тесты, просто передав дополнительный флаг компилятору, это поможет.
Тем не менее, я думаю, что отличная библиотека модульного тестирования делает гораздо больше, чем просто находит некоторые методы и запускает их. Взять, к примеру, QuickCheck на Haskell , который позволяет вам проверять такие вещи, как «для всех x и y
f (x, y) == f (y, x)
». QuickCheck лучше описать как генератор модульных тестов и позволяет вам тестировать вещи на более высоком уровне, чем «для этого входа, я ожидаю этот вывод». QuickCheck и Linq не так уж сильно отличаются - они оба являются предметно-ориентированными языками. Так что вместо того, чтобы связывать поддержку модульного тестирования с языком, почему бы не добавить функции, необходимые для практической реализации DSL? В результате вы получите не только модульное тестирование, но и лучший язык.источник
Потому что тестирование и, в частности, разработка, основанная на тестировании, - явление глубоко противоречивое.
Почти каждый программист начинает свою карьеру, полагая, что он гораздо лучше справляется со сложностью, чем на самом деле. Тот факт, что даже величайший программист не может писать большие и сложные программы без серьезных ошибок, если они не используют множество регрессионных тестов, серьезно разочаровывает и даже позорит многих практиков. Отсюда превалирующее нежелание регулярно проходить тестирование даже среди профессионалов, которые уже должны знать лучше.
Я думаю, что тот факт, что религиозное тестирование постепенно становится все более распространенным и ожидаемым, во многом связан с тем фактом, что с ростом емкости хранилища и вычислительной мощности создаются более крупные системы, чем когда-либо, а чрезвычайно большие системы особенно подвержены коллапсу сложности, что не может управляться без защитной сетки регрессионных тестов. В результате, даже особенно упрямые и заблуждающиеся разработчики теперь неохотно признают, что им нужно тестирование и что они всегда будут нуждаться в тестировании (если это звучит как признание на собрании АА, это вполне преднамеренно - для многих психологически трудно допустить необходимость сети безопасности) физические лица).
Большинство популярных на сегодняшний день языков датируются этим изменением отношения, поэтому у них мало встроенной поддержки тестов: у них есть
assert
, но нет контрактов. Я вполне уверен, что если тенденция сохранится, будущие языки будут иметь больше поддержки на уровне языка, чем на уровне библиотеки.источник
Многие языки поддерживают тестирование. С утверждает, что тесты могут провалиться. На этом большинство языков останавливаются, но в Eiffel и совсем недавно в Ada 2012 есть преинварианты (вещи, которые должны быть переданы аргументам функции) и postinvariants (вещи, которые должен передавать результат функции), при этом Ada предлагает возможность ссылаться на начальные аргументы в postinvariant. Ада 2012 также предлагает инварианты типа, поэтому всякий раз, когда метод вызывается для класса Ада, инвариант типа проверяется перед возвратом.
Это не тот тип полного тестирования, который может дать хорошая инфраструктура тестирования, но это важный тип тестирования, который языки могут лучше всего поддерживать.
источник
Некоторые сторонники строго типизированных функциональных языков утверждают, что эти возможности языка уменьшают или устраняют необходимость в модульных тестах.
Два, имхо, хороший пример этого из F # для Fun и Profit здесь и здесь
Лично я до сих пор верю в ценность модульных тестов, но есть некоторые веские аргументы. Например, если недопустимое состояние в коде непредставимо, тогда не только нет необходимости писать модульные тесты для этого случая, это невозможно.
источник
Я бы сказал, что вы пропустили добавление некоторых необходимых функций, потому что они не были выделены, как для модульного тестирования .
Например, модульное тестирование в C # в основном осуществляется с помощью атрибутов. Функция пользовательских атрибутов предоставляет богатый механизм расширения, который позволяет таким структурам, как NUnit, выполнять итерации и конкурировать с такими вещами, как теоретическое и параметризованное тестирование.
Это подводит меня ко второму важному моменту - мы недостаточно знаем о том, что делает тестируемость хорошей, чтобы превратить ее в язык. Темпы инноваций в тестировании намного быстрее, чем у других языковых конструкций, поэтому нам нужно иметь гибкие механизмы в наших языках, чтобы оставить свободу для инноваций.
Я пользователь, но не фанат TDD - в некоторых случаях он очень полезен, особенно для улучшения вашего дизайнерского мышления. Это не обязательно полезно для более крупных унаследованных систем - высокоуровневое тестирование с хорошими данными и автоматизацией, вероятно, принесет больше пользы наряду с сильной культурой проверки кода .
Другие соответствующие чтения:
источник