Comments 29
Извини за оффтоп, а если я не нажал на «Я соглашаюсь… бла бла бла», а нажал на ссылочку «Комментарии», это считается что я согласился, или нет?
Да. Я просто хочу, что бы не было copy-past этой статьи без указания автора (меня) и к тому же, что бы кто-либо делал на ней деньги. Думаю, это пожелания каждого автора на хабре.
>> Тест, который никогда не упал — бесполезный тест
Ничего подобного. Если я пишу тест, то я уверен, что потом, после рефакторинга эта часть кода не сломается. И могу не думать о ней.
Ничего подобного. Если я пишу тест, то я уверен, что потом, после рефакторинга эта часть кода не сломается. И могу не думать о ней.
Вы уверены в том, что если эта часть кода сломается, то тест завалиться. То есть уверенности придает его потенциальная способность завалиться.
Суть-то в том, что вы уверены, что часть кода не сломается, именно из-за теста. Т.к. он «упадет», если изменения в программе будут неправильные. Ценность теста именно в том, что он «падает» и сигнализирует о логической ошибке. А тест, который заведомо не будет падать, и писать незачем.
Вы, скорее всего, просто неправильно поняли предложение (или даже одно слово — «упал»), т.к. пишете-то все верно)
Вы, скорее всего, просто неправильно поняли предложение (или даже одно слово — «упал»), т.к. пишете-то все верно)
согласно законам Мерфи… если этот код никогда не должен падать, то в него обязательно закрадется ошибка.
понятно, что писать ok( 1 == 1 ) не нужно.
Но вот проверить, что функция вернула неотрицательное количество пользователей — стоит. Пусть этого и не может быть.
понятно, что писать ok( 1 == 1 ) не нужно.
Но вот проверить, что функция вернула неотрицательное количество пользователей — стоит. Пусть этого и не может быть.
Хорошая выжимка из книги Кента Бека «Экстремальное программирование».
Хотя основная идея это вселить смелость в разработчиков, что можно безболезненно менять любую часть проекта, проводить любой требуемый рефакторинг, а не откладывать все это и пользоваться устаревшими реализациями.
Хотя основная идея это вселить смелость в разработчиков, что можно безболезненно менять любую часть проекта, проводить любой требуемый рефакторинг, а не откладывать все это и пользоваться устаревшими реализациями.
Хорошая статья, но я не увидел в ней такой не популярный аспект как например то что тесты должны быть детерминированными, я что то упустил или уже это не актуально?
Это точно, но иногда этого сложно добиться, например, когда целью программы является моделирование и как следствее в ней активно используются случайные значения. В той задаче, с которой я сталкивался, мне повезло и после анализа я смог свести всю случайность в программе к случайным начальным данным, а сам алгоритм оказался детерминированным и мне удалось для него написать нормальные тесты.
Думаю, что когда-нибудь будет — мне эта тема интересна. А само утверждение это просто чистая интуиция, дело в том, что тестирование активно используется программистами, пишущими на динамичиских языках, то есть тестирование для них это замена типизации. Далее я ступаю на почву: согласно изоморфизму, типы есть теоремы, а программы доказатества; в нашем случае, тогда, тесты есть теоремы.
Завалиться, становиться — уберите мягкие знаки…
По теме: «если код будет написан после тестов, то это гарантирует, что тест завалится» — что-то я не поняла этого утверждения, можно поподробнее?
По теме: «если код будет написан после тестов, то это гарантирует, что тест завалится» — что-то я не поняла этого утверждения, можно поподробнее?
> Писать книги я не умею, да и опыта мало, но поделиться некоторыми аспектами использования unit тестов я могу
Точно не интересно попробовать формат пошире? Хотя книги по TDD есть, я думаю, тут ещё об очень многих аспектах можно порассуждать.
По крайней мере, я сам в повседневной практике усиленно пытаюсь внедрить TDD, но что-то всё время мешает. Сам я объясняю себе это сложностью и спецификой предметной области, но любой спец, скорее всего, легко раскритикует и объяснит как надо. Так что бы от хорошей книжки не отказался ;)
Точно не интересно попробовать формат пошире? Хотя книги по TDD есть, я думаю, тут ещё об очень многих аспектах можно порассуждать.
По крайней мере, я сам в повседневной практике усиленно пытаюсь внедрить TDD, но что-то всё время мешает. Сам я объясняю себе это сложностью и спецификой предметной области, но любой спец, скорее всего, легко раскритикует и объяснит как надо. Так что бы от хорошей книжки не отказался ;)
Вероятно, вам мешает выбранный вами тест-фреймворк:)
> но что-то всё время мешает
Если не сложно, не могли бы вы описать несколько примеров, что мешает?
Если не сложно, не могли бы вы описать несколько примеров, что мешает?
Довольно трудно сформулировать кратко :) Но попробую.
Для начала: мы пишем что-то вроде «конструктора» для создания систем искусственного интеллекта. По существующим спецификациям интерфейса пользователь должен написать свои собственные модули, потом система интегрируется в одно целое. Кроме того, мы поддерживаем инструментарий для отладки и анализа систем, а также выступаем в роли «пользователей», то есть сами пишем интеллектуальные агенты используя свой «конструктор».
Проблемы:
1) cложность и нечёткость предметной области. Если бы я писал библиотеку функций с понятным чётким поведением (тригонометрия, линейная алгебра) вопросов бы не было.
2) (редко, но бывает) ветвистость алгоритмов. Иногда у нас возникает куча кейсов типа «если-то», причём по отдельности каждый кейс выглядит довольно простым. Сочинять для такого тесты, честно говоря, ломает, потому что каждый случай тривиален, а чтобы покрыть большинство вариантов, уходит много кода. Покрыть же небольшую часть смысла мало, т.к. тогда тест становится не очень полезным.
3) в целом не очень большая польза от атомарных тестов в ИИ :) в большинстве случаев откомпилировать программу и заставить её работать по спецификации не очень трудно. Но оказывается, что работает интеллект плохо :) Приходится изменять параметры, влияющие на поведение, добавлять новые анализируемые факторы и т.п. То есть основной «дебаг» заключается в дополнительном анализе предметной области, а не в сверке со спецификацией.
4) (самый важный технический трабл). Наш «конструктор» можно представить себе ещё так. Есть инфраструктура с «дырками», для которой надо написать модули, затыкающие эти «дырки». Друг без друга ничего не работает. Чтобы запустить систему, нужны все модули (хотя бы в виде заглушек). Соответственно, чтобы тестировать инфраструктуру, нужны все модули (пусть хотя бы mock objects). А чтобы тестировать модули, нужна инфраструктура (впрочем, это уже не очень страшно). При этом всё развивается, иногда приходится менять слегка инфраструктуру под конкретный проект или добавлять в модули то, чего там быть не должно. В результате получается, что полноценный тестовый комплект может быть очень велик, включая в себя mock object едва ли не для любой сущности системы. Я склоняюсь к тому, чтобы рано или поздно стиснуть зубы и сделать эту работу. Но пока никак :)
5) (ерунда, но всё-таки) GUI-инструменты так тестировать вообще не получается.
В результате мы сейчас пользуемся в основном «feature-тестами». Собираем всю систему — от начала до конца, вначале состоящую из заглушек. Потом даём ей простые задания (это ведь интеллект, он должен выполнять какую-то работу в каких-то условиях). Если очередной модуль, который мы пишем, справляется со своей работой, то задание выполняется. Если не выполняется, ищем ошибку в модуле.
И так раскручиваем систему. Для готовой системы у нас есть непростые «задачки», для которых известен вход и выход, а также понятно, какой модуль реально должен эту задачу решить. Стало быть, если не решает, мы можем предположить, где именно баг…
В общем, сложно это всё, но интересно :)
Для начала: мы пишем что-то вроде «конструктора» для создания систем искусственного интеллекта. По существующим спецификациям интерфейса пользователь должен написать свои собственные модули, потом система интегрируется в одно целое. Кроме того, мы поддерживаем инструментарий для отладки и анализа систем, а также выступаем в роли «пользователей», то есть сами пишем интеллектуальные агенты используя свой «конструктор».
Проблемы:
1) cложность и нечёткость предметной области. Если бы я писал библиотеку функций с понятным чётким поведением (тригонометрия, линейная алгебра) вопросов бы не было.
2) (редко, но бывает) ветвистость алгоритмов. Иногда у нас возникает куча кейсов типа «если-то», причём по отдельности каждый кейс выглядит довольно простым. Сочинять для такого тесты, честно говоря, ломает, потому что каждый случай тривиален, а чтобы покрыть большинство вариантов, уходит много кода. Покрыть же небольшую часть смысла мало, т.к. тогда тест становится не очень полезным.
3) в целом не очень большая польза от атомарных тестов в ИИ :) в большинстве случаев откомпилировать программу и заставить её работать по спецификации не очень трудно. Но оказывается, что работает интеллект плохо :) Приходится изменять параметры, влияющие на поведение, добавлять новые анализируемые факторы и т.п. То есть основной «дебаг» заключается в дополнительном анализе предметной области, а не в сверке со спецификацией.
4) (самый важный технический трабл). Наш «конструктор» можно представить себе ещё так. Есть инфраструктура с «дырками», для которой надо написать модули, затыкающие эти «дырки». Друг без друга ничего не работает. Чтобы запустить систему, нужны все модули (хотя бы в виде заглушек). Соответственно, чтобы тестировать инфраструктуру, нужны все модули (пусть хотя бы mock objects). А чтобы тестировать модули, нужна инфраструктура (впрочем, это уже не очень страшно). При этом всё развивается, иногда приходится менять слегка инфраструктуру под конкретный проект или добавлять в модули то, чего там быть не должно. В результате получается, что полноценный тестовый комплект может быть очень велик, включая в себя mock object едва ли не для любой сущности системы. Я склоняюсь к тому, чтобы рано или поздно стиснуть зубы и сделать эту работу. Но пока никак :)
5) (ерунда, но всё-таки) GUI-инструменты так тестировать вообще не получается.
В результате мы сейчас пользуемся в основном «feature-тестами». Собираем всю систему — от начала до конца, вначале состоящую из заглушек. Потом даём ей простые задания (это ведь интеллект, он должен выполнять какую-то работу в каких-то условиях). Если очередной модуль, который мы пишем, справляется со своей работой, то задание выполняется. Если не выполняется, ищем ошибку в модуле.
И так раскручиваем систему. Для готовой системы у нас есть непростые «задачки», для которых известен вход и выход, а также понятно, какой модуль реально должен эту задачу решить. Стало быть, если не решает, мы можем предположить, где именно баг…
В общем, сложно это всё, но интересно :)
Скажите, пожалуйста, где вы работаете — я с радостью пойду к вам в команду. Почему-то везде, где мне приходилось побывать, слова «тесты» «юнит-тестинг» и т.п. вызывали у менеджмента или непонимание, или полное отторжение, аля «мы не успеем сделать программу».
>>>К сожалению в статически типизированные языки не дружат с REPL
Не все. Хаскель и F#, например, дружат. У последнего в VS есть удобная консоль
Не все. Хаскель и F#, например, дружат. У последнего в VS есть удобная консоль
> Тест, который никогда не упал — бесполезный тест
Вы пытаетесь доказать это утверждение или это аксиома?
> Если ввести условие, что тесты не являются бесполезными,
> то тогда следует, что хороший тест должен хоть раз завалить программу.
У вас две этих фразы ссылаются друг на друга. Вы утверждаете что
упавший тест не бесполезен предполагая что
тест не бесполезен и получаете то что тест должен падать.
«ты не прав, потом что предположем, что ты не прав, следовательно ты не прав» :-)
На самом деле мне кажется это можно доказать ссылаясь на старую истину (и принимая ее как аксиому), что невозможно написать программу без ошибок и следовательно, если тест не падает, значит он просто не обнаруживает ошибку в программе, которую тестирует.
Вы пытаетесь доказать это утверждение или это аксиома?
> Если ввести условие, что тесты не являются бесполезными,
> то тогда следует, что хороший тест должен хоть раз завалить программу.
У вас две этих фразы ссылаются друг на друга. Вы утверждаете что
упавший тест не бесполезен предполагая что
тест не бесполезен и получаете то что тест должен падать.
«ты не прав, потом что предположем, что ты не прав, следовательно ты не прав» :-)
На самом деле мне кажется это можно доказать ссылаясь на старую истину (и принимая ее как аксиому), что невозможно написать программу без ошибок и следовательно, если тест не падает, значит он просто не обнаруживает ошибку в программе, которую тестирует.
Да, не хорошо получилось.
Смысл в том, что если вы решили использовать тесты, то вы уже считаете, что тесты это хорошо и уже считаете их применение оправданным. Взявь эту уверенность за аксиому, получаем следствие про то, что тесты должны падать. В итоге можно читать следующем образом: если я верю в то, что тестирование приносит пользу, то я обязан верить и то, что тест, который никогда не завалиться — бесполезный тест. Надеюсь теперь стало яснее.
Смысл в том, что если вы решили использовать тесты, то вы уже считаете, что тесты это хорошо и уже считаете их применение оправданным. Взявь эту уверенность за аксиому, получаем следствие про то, что тесты должны падать. В итоге можно читать следующем образом: если я верю в то, что тестирование приносит пользу, то я обязан верить и то, что тест, который никогда не завалиться — бесполезный тест. Надеюсь теперь стало яснее.
Sign up to leave a comment.
Непопулярные аспекты тестирования