Как вы тестируете модульный тест? [закрытый]
Я наблюдал за веб-трансляциями Роба Коннери в приложении MVCStoreFront, и я заметил, что он тестировал даже самые мирские вещи, такие как:
public Decimal DiscountPrice
{
get
{
return this.Price - this.Discount;
}
}
будет иметь тест, как:
[TestMethod]
public void Test_DiscountPrice
{
Product p = new Product();
p.Price = 100;
p.Discount = 20;
Assert.IsEqual(p.DiscountPrice,80);
}
В то время как я все для модульного тестирования, я иногда задаюсь вопросом, действительно ли эта форма первой разработки теста полезна, например, в реальном процессе у вас есть 3-4 слоя над вашим кодом (бизнес-запрос, документ требований, документ архитектуры), где фактический определенное бизнес-правило (цена скидки - это цена-скидка) может быть неверно определено.
Если это так, ваш модульный тест ничего не значит для вас.
кроме того, модульный тест является еще одной точкой отказа:
[TestMethod]
public void Test_DiscountPrice
{
Product p = new Product();
p.Price = 100;
p.Discount = 20;
Assert.IsEqual(p.DiscountPrice,90);
}
Теперь тест испорчен. Очевидно, что в простом тесте это не имеет большого значения, но, скажем, мы тестировали сложное бизнес-правило. Что мы здесь приобретаем?
быстро вперед 2 лет в жизнь применения, когда обслуживание разработчики поддерживают его. Теперь бизнес меняет свое правило, и тест снова ломается, какой-то новобранец-разработчик затем исправляет тест неправильно...теперь у нас есть еще одна точка отказа.
все, что я вижу, это более возможные точки отказа, без реального выгодного возврата, если цена со скидкой неверна, тестовая команда все равно найдет проблему, как модульное тестирование сохранило какую-либо работу?
чего мне здесь не хватает? Пожалуйста, научите меня любить TDD, так как мне трудно принять это так же полезно до сих пор. Я тоже хочу, потому что я хочу оставаться прогрессивным, но это просто не имеет смысла для меня.
EDIT: несколько человек продолжают упоминать, что тестирование помогает обеспечить соблюдение спецификации. По моему опыту, спецификация также была неправильной, чаще всего, но, возможно, я обречен работать в организации, где спецификации написаны людьми, которые не должны писать спецификации.
17 ответов:
во-первых, тестирование похоже на безопасность-вы никогда не можете быть на 100% уверены, что у вас есть это, но каждый уровень добавляет больше уверенности и рамки для более легкого устранения проблем, которые остаются.
во-вторых, вы можете сломать тесты на подпрограммы, которые затем могут быть проверены. Когда у вас есть 20 подобных тестов, создание (тестируемой) подпрограммы означает, что ваш основной тест-это 20 простых вызовов подпрограммы, которые с большей вероятностью будут правильными.
в-третьих, некоторые утверждают, это TDD решает данную проблему. То есть, если вы просто пишете 20 тестов, и они проходят, Вы не совсем уверены, что они действительно что-то тестируют. Но если каждый тест вы писали изначально ошибка, а затем вы исправили его, то вы гораздо более уверены, что это действительно тестирование вашего кода. ИМХО это взад и вперед занимает больше времени, чем это стоит, но это процесс, который пытается решить вашу проблему.
неправильный тест вряд ли нарушит ваш производственный код. По крайней мере, не хуже, чем вообще без теста. Таким образом, это не "точка отказа": тесты не должны быть правильными, чтобы продукт действительно работал. Возможно, они должны быть правильными, прежде чем он будет подписан как рабочий, но процесс исправления любых сломанных тестов не ставит под угрозу ваш код реализации.
вы можете думать о тестах, даже тривиальных тестах, подобных этим, как о втором мнении, что код должен делать. Одно мнение-это тест, другое-реализация. Если они не согласны, то вы знаете, что у вас проблемы и вы присмотритесь.
Это также полезно, если кто-то в будущем хочет реализовать тот же интерфейс с нуля. Они не должны читать первую реализацию, чтобы знать, что означает скидка, и тесты действуют как однозначная резервная копия любого письменного описания интерфейса, который у вас может быть.
Что сказал, Ты время для обмена. Если есть другие тесты, которые вы могли бы писать, используя время, которое вы экономите, пропуская эти тривиальные тесты, возможно, они будут более ценными. Это зависит от вашей тестовой установки и характера приложения, на самом деле. Если скидка важна для приложения, то вы все равно поймаете любые ошибки в этом методе в функциональном тестировании. Все модульное тестирование позволяет вам поймать их в тот момент, когда вы тестируете этот блок, когда местоположение ошибки будет сразу же очевидно, вместо этого из ожидания, пока приложение не будет интегрировано вместе и расположение ошибки может быть менее очевидны.
кстати, лично я бы не использовал 100 в качестве цены в тестовом случае (или, скорее, если бы я это сделал, я бы добавил еще один тест с другой ценой). Причина в том, что кто-то в будущем может подумать, что скидка должна быть в процентах. Одной из целей тривиальных тестов, подобных этому, является обеспечение того, чтобы ошибки при чтении спецификации были исправленный.
[относительно редактирования: я думаю, что это неизбежно, что неправильная спецификация является точкой отказа. Если вы не знаете, что приложение будет делать, то, скорее всего, не получится. Но написание тестов для отражения спецификации не увеличивает эту проблему, она просто не может ее решить. Таким образом, вы не добавляете новые точки отказа, вы просто представляете существующие ошибки в коде вместо
вафельницыдокументация.]
все, что я вижу, это более возможные точки отказа, без реального выгодного возврата, если цена со скидкой неверна, команда тестирования все равно найдет проблему, как модульное тестирование сохранило какую-либо работу?
модульное тестирование на самом деле не должно сохранять работу, оно должно помочь вам найти и предотвратить ошибки. Это больше работает, но это правильный вид работы. Он думает о вашем коде на самых низких уровнях детализации и написание тестовых случаев, которые доказывают, что она работает в ожидается условия, для заданного набора входных данных. Он изолирует переменные, так что вы можете сохранить времени в нужном месте, когда ошибка не представить себя. Это экономия этот набор тестов, так что вы можете использовать их снова и снова, когда вам нужно внести изменения в будущем.
Я лично думаю, что большинство методик не так много шагов удалены от программное обеспечение культа груза инженерный, TDD включен, но вам не нужно придерживаться строгого TDD, чтобы воспользоваться преимуществами модульного тестирования. Держите хорошие части и выбрасывайте части, которые приносят мало пользы.
наконец, ответ на ваш вопрос титульной "как вы тестируете модульный тест?
модульные тесты существуют так, что ваши единицы (методы) делают то, что вы ожидаете. Написание теста в первую очередь заставляет вас думать о том, что вы ожидаете до вы пишете код. Думать, прежде чем делать это всегда хорошая идея.
модульные тесты должны отражать бизнес-правил. Конечно, в коде могут быть ошибки, но написание теста сначала позволяет вам написать его с точки зрения бизнес-правила до того, как будет написан какой-либо код. Написание теста после этого, я подумайте, скорее всего, приведет к ошибке вы описываете, потому что вы знаю как код реализует его и соблазн просто убедиться, что реализация правильна-не то, что намерение правильно.
кроме того, модульные тесты-это только одна форма-и самая низкая, при этом-тестов, которые вы должны писать. Интеграционные тесты и приемочные тесты также должны быть написаны, последний заказчиком, если это возможно, чтобы убедиться, что система работает так, как она есть ожидаемый. Если вы обнаружите ошибки во время этого тестирования, вернитесь и напишите модульные тесты (которые не работают), чтобы проверить изменение функциональности, чтобы заставить ее работать правильно, а затем измените свой код, чтобы пройти тест. Теперь у вас есть регрессионные тесты, которые фиксируют ваши исправления ошибок.
[EDIT]
еще одна вещь,которую я нашел с помощью TDD. Это почти заставляет хороший дизайн по умолчанию. Это происходит потому, что высоко сочетании конструкции практически невозможно модульного тестирования в изоляции. Это не займет очень долго используя TDD, чтобы понять, что использование интерфейсов, инверсия управления и инъекция зависимостей-все шаблоны, которые улучшат ваш дизайн и уменьшат сцепление-действительно важны для тестируемого кода.
в то время как, я все для модульного тестирования, я иногда интересно, если эта форма теста первое развитие действительно полезно...
небольшие, тривиальные тесты, подобные этому, могут быть "канарейкой в угольной шахте" для вашей кодовой базы, предупреждая об опасности, пока не стало слишком поздно. Тривиальные тесты полезны, чтобы держать вокруг, потому что они помогают вам получить правильные взаимодействия.
например, подумайте о тривиальном тесте, поставленном на место, чтобы узнать, как использовать API, который вы используете незнакомое. Если этот тест имеет какое-либо отношение к тому, что вы делаете в коде, который использует API "для реального", полезно сохранить этот тест. Когда API выпускает новую версию, и вам нужно обновить. Теперь у вас есть предположения о том, как вы ожидаете, что API будет вести себя записанным в исполняемом формате, который можно использовать для перехвата регрессий.
...[I]N реальный процесс, у вас есть 3-4 слои над вашим кодом (бизнес Запрос, Требования Документ, Архитектурный документ), где фактическое определенное бизнес-правило (скидка Цена цена - скидка) может быть неверно определено. Если такова ситуация, модульный тест ничего не значит для вас.
Если вы кодировали в течение многих лет без написания тестов, это может быть не сразу очевидно для вас, что есть какое-либо значение. Но если вы считаете, что лучший способ работы - это "выпускать рано, выпускать часто" или "гибкий" , в котором вы хотите иметь возможность развертывания быстро / непрерывно, тогда ваш тест определенно что-то значит. Единственный способ сделать это-узаконить каждое изменение, которое вы вносите в код с помощью теста. Независимо от того, насколько мал тест, как только у вас есть зеленый набор тестов, вы теоретически можете развернуть его. См. также "непрерывное производство" и "бесконечной беты."
вам не нужно быть "первым тестом", чтобы иметь такое мышление, но это, как правило, самый эффективный способ добраться туда. Когда вы делаете TDD, вы запираетесь в небольшой двух - трехминутный красно-зеленый цикл рефакторинга. Ни в коем случае вы не можете остановиться и уйти, и у вас на руках полный беспорядок, который займет час, чтобы отладить и собрать вместе.
кроме того, ваш модульный тест-это другой точка сбоя...
удачный тест, который демонстрирует сбой в системе. Неудачный тест предупредит вас об ошибке в логике теста или в логике вашей системы. Цель вашего тесты должны сломать ваш код или доказать, что один сценарий работает.
Если вы пишете тесты после код, вы рискуете написать тест ,который является "плохим", потому что для того, чтобы увидеть, что ваш тест действительно работает, вам нужно увидеть, что он сломан и работает. Когда вы пишете тесты после кода, это означает, что вам нужно "запустить ловушку" и ввести ошибку в код, чтобы увидеть сбой теста. Большинство разработчиков не только обеспокоены этим, но и утверждают, что это пустая трата времени время.
что мы получаем здесь?
есть определенно преимущество делать вещи таким образом. Майкл перья определяет " унаследованный код "как" непроверенный код."Когда вы принимаете этот подход, вы узакониваете каждое изменение, которое вы вносите в свою кодовую базу. Это более строго, чем не использовать тесты, но когда дело доходит до поддержания большой кодовой базы, он платит за себя.
говоря о перьях, есть два больших ресурса, которые вы должны проверить в отношении это:
оба они объясняют, как работать с этими типами практик и дисциплин в проектах, которые не являются "Гринфилдом"."Они предоставляют методы для написания тестов вокруг тесно связанных компонентов, жестко связанных зависимостей и вещей, которые вы не обязательно контролируете. Это все о поиске "швы" и тестирование вокруг.
[I]f цена со скидкой неверна, тестовая команда все равно найдет проблему, как модульное тестирование сохранило какую-либо работу?
такие привычки, как эти, как инвестиции. Возвраты не являются немедленными; они накапливаются с течением времени. Альтернативой не тестированию является, по сути, принятие на себя долга не в состоянии поймать регрессии, ввести код без страха ошибок интеграции или управлять проектными решениями. Красота-это ты узаконить все изменения в коде.
что мне здесь не хватает? Пожалуйста, научите я люблю TDD, так как мне тяжело время принимать его как полезное до сих пор. Я хочу тоже, потому что хочу остаться прогрессивный, но это просто не делает смысл для меня.
Я смотрю на это как на профессиональную ответственность. Это идеал, к которому нужно стремиться. Но это очень трудно и утомительно. Если вы заботитесь об этом, и чувствуете, что вы не должны создавать код то есть не проверено, вы сможете найти силу воли, чтобы узнать хорошие привычки тестирования. Одна вещь, которую я сейчас много делаю (как и другие), - это timebox сам час, чтобы написать код без каких-либо тестов вообще, а затем иметь дисциплину, чтобы выбросить его. Это может показаться расточительным, но это не совсем. Дело не в том, что физические упражнения стоят компании физических материалов. Это помогло мне понять проблему и как написать код таким образом, чтобы он был как более качественным, так и тестируемым.
мой совет в конечном итоге будет заключаться в том, что если у вас действительно нет желания быть хорошим в этом, то не делайте этого вообще. Плохие тесты, которые не поддерживаются, не работают хорошо и т. д. может быть хуже, чем не иметь никаких тестов. Трудно учиться на собственных, и вы, вероятно, не понравится, но это будет почти невозможно научиться, если у вас нет желания делать это, или не может видеть достаточно в этом, чтобы оправдать инвестиции.
несколько человек продолжают упоминать, что тестирование помогает обеспечить соблюдение спецификации. Оно имеет моему опыту, спецификация ошибался также, чаще, чем не...
клавиатура разработчика находится там, где резина встречается с дорогой. Если спецификация неверна, и вы не поднимаете флаг на ней, то весьма вероятно, что вас обвинят в этом. Или, по крайней мере, ваш код будет. Дисциплина и строгость, участвующие в тестировании трудно придерживаться. Это совсем не просто. Это требует практики, много обучения и много ошибки. Но в конце концов это окупается. В быстро развивающемся, быстро меняющемся проекте это единственный способ спать ночью, независимо от того, замедляет ли он вас.
еще одна вещь, о которой следует подумать здесь, заключается в том, что методы, которые в основном совпадают с тестированием, были доказаны в прошлом: "чистая комната" и "дизайн по контракту", как правило, производят одни и те же типы конструкций "мета"-кода, которые делают тесты, и применяют их в разных точках. Ни один из этих методов серебряные пули, и строгость будет стоить вам в конечном счете в объеме функций, которые вы можете доставить с точки зрения времени на рынок. Но дело не в этом. Речь идет о том, чтобы поддерживать то, что вы делаете. И это очень важно для большинства проектов.
модульное тестирование работает очень похоже на двойной Бухгалтерский учет. Вы утверждаете одно и то же (бизнес-правило) двумя совершенно разными способами (как запрограммированные правила в вашем производственном коде и как простые, репрезентативные примеры в ваших тестах). Это очень маловероятно, что вы делаете тот же ошибка в обоих, поэтому, если они оба согласны друг с другом, маловероятно, что вы ошиблись.
Как тестирование будет стоить усилий? По моему опыту как минимум в четырех способы, по крайней мере, при выполнении тестовой разработки:
- это поможет вам придумать хорошо разъединенный дизайн. Вы можете только модульный тестовый код, который хорошо развязан;
- это поможет вам определить, когда вы сделали. Необходимость указывать необходимое поведение в тестах помогает не создавать функциональность, которая вам на самом деле не нужна, а определить, когда функциональность завершена;
- это дает вам страховочную сетку для рефакторинга, что делает код гораздо более сговорчивым к переменам; и
- это экономит вам много времени на отладку, что ужасно дорого (я слышал оценки, что традиционно разработчики тратят до 80% своего времени на отладку).
большинство модульных тестов, Тест на предположениях. В этом случае цена скидки должна быть ценой минус скидка. Если ваши предположения неверны, я уверен, что ваш код также неверен. А если вы совершите глупую ошибку, то тест провалится и вы его исправите.
Если правила изменятся, тест не пройдет, и это хорошо. Так что вы должны изменить тест тоже в этом случае.
Как правило, если тест завершается неудачей сразу (и вы не используете test first design), либо тест или код неверный (или оба, если у вас плохой день). Вы используете здравый смысл (и possilby спецификации), чтобы исправить оскорбительный код и повторно запустить тест.
Как сказал Джейсон, тестирование-это безопасность. И да, иногда они вводят дополнительную работу из-за ошибочных тестов. Но в большинстве случаев они являются огромными экономителями времени. (И у вас есть прекрасная возможность наказать парня, который нарушает тест (речь идет о резиновой курице)).
проверьте все, что вы можете. Даже тривиальные ошибки, такие как забывание конвертировать метры в ноги, могут иметь очень дорогие побочные эффекты. Написать тест, написать код для его проверки, получить его, чтобы пройти, двигаться дальше. Кто знает в какой-то момент в будущем, кто-то может изменить код скидки. Тест может обнаружить проблему.
Я вижу, что юнит-тесты и код как имеющие симбиотические отношения. Проще говоря: одно проверяет другое. И оба тестируют разработчика.
помните, что стоимость исправления дефектов увеличивается (экспоненциально), поскольку дефекты живут через цикл разработки. Да, команда тестирования может поймать дефект, но (как правило) потребуется больше работы, чтобы изолировать и исправить дефект с этой точки, чем если бы модульный тест не удался, и будет легче ввести другие дефекты при его исправлении, если у вас нет модульных тестов для запуска.
это обычно легче увидеть с чем-то большим, чем тривиальный пример ... и с тривиальные примеры, ну, если вы каким-то образом испортите модульный тест, человек, просматривающий его, поймает ошибку в тесте или ошибку в коде, или и то, и другое. (Они рассматриваются, не так ли?) Как tvanfosson указывает модульное тестирование-это только одна часть плана шко.
в некотором смысле, модульные тесты являются страховкой. Они не гарантируют, что вы поймаете каждый дефект, и иногда может показаться, что вы тратите на них много ресурсов, но когда они ловят дефекты, которые вы можете исправить, вы будете тратить намного меньше, чем если бы не тесты и исправить все дефекты по течению.
Я понимаю вашу точку зрения, но она явно завышена.
ваш аргумент в основном: тесты вводят сбой. Поэтому тесты-это плохо / пустая трата времени.
хотя это может быть верно в некоторых случаях, это вряд ли большинство.
TDD предполагает: больше тестов = меньше сбоев.
тесты скорее чтобы поймать точки отказа, чем ввести их.
еще больше автоматизации может помочь здесь ! Да, написание модульных тестов может быть много работы, чтобы использовать некоторые инструменты, чтобы помочь вам. Посмотрите на что-то вроде Pex, от Microsoft, если вы используете .Net Он будет автоматически создавать наборы модульных тестов для вас, изучая ваш код. Он будет придумывать тесты, которые дают хорошее покрытие, пытаясь охватить все пути через ваш код.
конечно, просто глядя на ваш код, он не может знать, что вы на самом деле пытаетесь сделать, так это не знаю, правильно это или нет. Но, он будет генерировать интересные тестовые случаи для вас, и вы можете изучить их и посмотреть, если он ведет себя так, как вы ожидаете.
Если вы затем пойдете дальше и напишете параметризованные модульные тесты (вы можете думать об этом как о контрактах, на самом деле), он будет генерировать конкретные тестовые случаи из них, и на этот раз он может знать, что что-то не так, потому что ваши утверждения в ваших тестах потерпят неудачу.
Я немного подумал о хорошем способе ответить на этот вопрос, и хотел бы провести параллель с научным методом. ИМО, вы могли бы перефразировать этот вопрос: "Как вы экспериментируете эксперимент?"
эксперименты подтверждают эмпирические предположения (гипотезы) о физической Вселенной. Модульные тесты проверяют предположения о состоянии или поведении кода, который они вызывают. Мы можем говорить об обоснованности эксперимента, но это потому, что мы знаем, через многочисленные другие эксперименты, что-то не подходит. У него нет обоих внешняя валидность и эмпирических доказательств. Мы не разрабатываем новый эксперимент для проверки или проверки достоверности эксперимент, но мы можем спроектировать совершенно новый эксперимент.
Так как эксперименты, мы не описываем валидность модульного теста на основе того, проходит ли он сам модульный тест. Наряду с другими модульными тестами, это описывает предположения, которые мы делаем о тестируемой системе. Кроме того, как и эксперименты, мы стараемся удалить как можно больше сложности из того, что мы тестируем. " как можно проще, но не проще."
в отличие от экспериментов, у нас есть трюк в рукаве, чтобы проверить, что наши тесты действительны, кроме просто конвергентной валидности. Мы можем умно ввести ошибку, которую, как мы знаем, должен поймать тест, и посмотреть, действительно ли тест провалился. (Если бы только мы если бы мы могли сделать это в реальном мире, мы бы гораздо меньше зависели от этой конвергентной валидности!) Более эффективный способ сделать это-наблюдать, как ваш тест терпит неудачу перед его реализацией (красный шаг в Красный, Зеленый, Рефакторинг).
вы должны использовать правильную парадигму при написании тестов.
- начните с первого написания тестов.
- убедитесь, что они не начать с него.
- получить их, чтобы пройти.
- проверка кода перед проверкой кода (убедитесь, что тесты проверены.)
вы не можете всегда быть уверены, но они улучшают общие тесты.
даже если вы не тестируете свой код, он обязательно будет протестирован в производстве вашими пользователями. Пользователи очень творчески пытаются разбить ваш софт и найти даже некритические ошибки.
исправление ошибок в производстве намного дороже, чем решение проблем на этапе разработки. Как побочный эффект, вы потеряете доход из-за исхода клиентов. Вы можете рассчитывать на 11 потерянных или не приобретенных клиентов для 1 сердитого клиента.