Практика Test-Driven Development
От: 0K Ниоткуда  
Дата: 19.09.08 21:54
Оценка:
Заинтересовался сабжем... Но, честно сказать, практически не могу представить как сделать так, чтобы сабж был полезен и написание тестов было не сложнее написания самой программы.

Попробуем рассмотреть на простом практическом примере. Предположим, нужно сделать систему для пополнения счета телефона.

Упростим максимально и разделим на этапы (укажем только 4 первых шага):

1. Ввод номера телефона и суммы пользователем (на сайте).
2. Проверка существования номера (XML-запрос к сервису оператора).
3. Проверка суммы (от ... до).
4. Занесение операции в базу данных (ИД, номер телефона, сумма, статус 0 (не оплачено)) и возврат ИД

Что нужно делать дальше? Какие тесты писать?
Re: Практика Test-Driven Development
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 20.09.08 05:02
Оценка: 5 (2)
Здравствуйте, 0K, Вы писали:

0K>Заинтересовался сабжем... Но, честно сказать, практически не могу представить как сделать так, чтобы сабж был полезен и написание тестов было не сложнее написания самой программы.


0K>Попробуем рассмотреть на простом практическом примере. Предположим, нужно сделать систему для пополнения счета телефона.


0K>Упростим максимально и разделим на этапы (укажем только 4 первых шага):


0K>1. Ввод номера телефона и суммы пользователем (на сайте).

0K>2. Проверка существования номера (XML-запрос к сервису оператора).
0K>3. Проверка суммы (от ... до).
0K>4. Занесение операции в базу данных (ИД, номер телефона, сумма, статус 0 (не оплачено)) и возврат ИД

0K>Что нужно делать дальше? Какие тесты писать?


а)делаем моки для проверятеля номера телефона, проверятеля суммы и репозитария бд.
б)пишем тест который проверяет правильность реакции интерфейса на ввод корректных номера и суммы
в)пишем тест который проверяет правильность вызова метода репозитария для занесения данных в базу (корректность параметров метода)
д)пишем тест который проверяет правильность реакции интерфейса на ввод НЕкорректных номера и суммы
е)пишем тест проверятеля суммы
ж)пишем тест проверятеля номера номера телефона: подпихиваем ему различные XML-доккументы. Если проверятель телефона толлько выполняет запрос и возвращает XML, то тестить его не обзательно
Re[2]: Практика Test-Driven Development
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 20.09.08 05:15
Оценка: 5 (2)
Здравствуйте, gandjustas, Вы писали:

G>Здравствуйте, 0K, Вы писали:


0K>>Заинтересовался сабжем... Но, честно сказать, практически не могу представить как сделать так, чтобы сабж был полезен и написание тестов было не сложнее написания самой программы.


0K>>Попробуем рассмотреть на простом практическом примере. Предположим, нужно сделать систему для пополнения счета телефона.


0K>>Упростим максимально и разделим на этапы (укажем только 4 первых шага):


0K>>1. Ввод номера телефона и суммы пользователем (на сайте).

0K>>2. Проверка существования номера (XML-запрос к сервису оператора).
0K>>3. Проверка суммы (от ... до).
0K>>4. Занесение операции в базу данных (ИД, номер телефона, сумма, статус 0 (не оплачено)) и возврат ИД

0K>>Что нужно делать дальше? Какие тесты писать?


G>а)делаем моки для проверятеля номера телефона, проверятеля суммы и репозитария бд.

G>б)пишем тест который проверяет правильность реакции интерфейса на ввод корректных номера и суммы
G>в)пишем тест который проверяет правильность вызова метода репозитария для занесения данных в базу (корректность параметров метода)
G>д)пишем тест который проверяет правильность реакции интерфейса на ввод НЕкорректных номера и суммы
G>е)пишем тест проверятеля суммы
G>ж)пишем тест проверятеля номера номера телефона: подпихиваем ему различные XML-доккументы. Если проверятель телефона толлько выполняет запрос и возвращает XML, то тестить его не обзательно

После написания кода стоит написать еще интеграционный тест, работающий на реальной базе и ииспольющий "реальный" (самописный) сервис валидации номера.
Re[3]: Практика Test-Driven Development
От: 0K Ниоткуда  
Дата: 20.09.08 09:17
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>После написания кода стоит написать еще интеграционный тест, работающий на реальной базе и ииспольющий "реальный" (самописный) сервис валидации номера.


Подскажите, пожалуйста. Чем можно произвести интеграционное тестирование WinForm.Net и ASP.NEt приложений?
Re[4]: Практика Test-Driven Development
От: Maxim Golov Голландия  
Дата: 20.09.08 14:01
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Здравствуйте, gandjustas, Вы писали:


G>>После написания кода стоит написать еще интеграционный тест, работающий на реальной базе и ииспольющий "реальный" (самописный) сервис валидации номера.


0K>Подскажите, пожалуйста. Чем можно произвести интеграционное тестирование WinForm.Net и ASP.NEt приложений?


Selenium очень даже хвалят.
Re[4]: Практика Test-Driven Development
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 20.09.08 14:34
Оценка: 5 (2)
Здравствуйте, 0K, Вы писали:

0K>Здравствуйте, gandjustas, Вы писали:


G>>После написания кода стоит написать еще интеграционный тест, работающий на реальной базе и ииспольющий "реальный" (самописный) сервис валидации номера.


0K>Подскажите, пожалуйста. Чем можно произвести интеграционное тестирование WinForm.Net и ASP.NEt приложений?


В тестовых фреймворках есть утилиты для запуска тестов как из командной строки, так и с гуевым интерфесом. В 2008 студии версии Pro и выше есть тестовый фреймворк (mstest), также можно использовать NUnit.

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

Есть еще тестирование интерфейса, но далеко не всегда его можно выполнить автоматически. Для веба есть, указанный выше Selenium, а также есть библиотека WatiN для .NET. При тестировании интерфейса проверяется не правильность работы кода программы, а правильность работы интерфейса.

Для нормального тестирования ASP.NET приложений лучше использовать ASP.NET MVC. При использовании WebForms придется самостоятельно выносить всю логику в отдельную сборку не давать ей "проникать" в интерфейс.
Re: Практика Test-Driven Development
От: LordMAD Россия  
Дата: 20.09.08 21:01
Оценка: 7 (2) -1
Здравствуйте, 0K, Вы писали:

0K>Заинтересовался сабжем... Но, честно сказать, практически не могу представить как сделать так, чтобы сабж был полезен и написание тестов было не сложнее написания самой программы.


Тестирование кода должно занимать у программистов не более 25% времени работы над проектом (причем сюда входят все виды тестирования, которые выполняются программистами: unit-тесты, интеграционное тестирование т.д.). Это противоречит духу TDD, насколько я понимаю: если Вы пишите тест до кода, гарантировать такого соотношения времени нельзя в сколько-нибудь не тривиальном случае. Однако тестирование — не самоцель, так как тестирование не доказывает отсутствие ошибок и не приводит к улучшению качества кода, как известно (об этом неплохо писал Макконнелл в его Code Complete). Если Вы чувствуете, что тест за малое время написать нельзя:
1. Попробуйте сменить инструменты, используемые для тестирования — Ваши, видимо, не эффективны. Предпочитайте инструменты тестирования, которые сами могут создавать тесты — чем меньше их придется писать программисту, тем лучше.
2. Разграничьте то, что надо тестировать и то, что хорошо бы тестировать. Тестируйте то, что имеет долгое время жизни (будет использоваться годами, возможно, не в одном проекте). Лучше хорошо протестировать то, что будет использоваться в десятках версий, чем кое-как протестировать и то, что используется часто и то, что перестанет существовать в следующей версии (тех, у кого время "резиновое" — это, конечно, не касается). Для того, что хорошо бы протестировать обдумайте альтернативные (менее затратные по времени, чем тестирование) варианты: например, можете назначить на code review такого участка кода больше людей (но не переусердствуйте — тут нужно помнить во сколько раз они будут быстрее читать код, чем можно было бы писать тесты для него). Помните, что существует много способов обнаружения дефектов помимо тестирования — выбирайте самый эффективный из них для каждой конкретной ситуации.
3. Не требуйте от себя и от других, чтобы тесты писались в определенные этапы. Например, если Вы хотите, чтобы в момент помещения в VCS тесты уже были, это может привести к тому, что такое правило просто не будет соблюдаться по разным "уважительным" причинам. Особенно хорошо это заметно, когда у программистов свободное расписание — тогда при наличии на рабочем месте тех коллег, которые нужны для обсуждения рабочих вопросов, лучше это время потратить на это, а тесты, как правило, не требуют согласования каких либо вопросов с другими, поэтому их написание можно откладывать на время, когда брифинги и прочие обсуждения не проводятся.
4. TDD предусматривает написание лишь-бы-какого кода для прохождения теста и последующий рефакторинг — но следует помнить, что большинство программистов не любит выбрасывать код, да и современные инструменты рефакторинга далеки от совершенства, так что эти "издержки" TDD надо учитывать.
5. Как известно, предварительное написание тестов, позволяет найти проблемы в требованиях на более ранних этапах. Но не забывайте, что этим программист вынужден просто тестировать не свою работу, а работу того, кто отвечает за требования, поэтому может оказаться так, что в то время как один человек экономит 15 минут, целая группа разработчиков будет тратить существенно большее время на написание тестов — очень часто можно найти более эффективные способы проверки требований.
6. Многие из так называемых "чистых тестов" (проверок того, работает ли код) можно заменить, например, дизайном по контракту, на который нужно меньше времени. В то время как более полезны с точки зрения нахождения ошибок "грязные тесты" (попытки нарушить работу кода), которые к тому же и тестируют "дизайн по контракту".
7. Есть люди, которым удется хорошо писать тесты, а есть такие у которых баги проходят через тесты как вода сквозь пальцы — такие особенности нужно учитывать (см. деление на то, что надо тестировать и то, что хорошо бы тестировать в п.2): не надо заставлять людей делать ненужную работу — писать плохие тесты — это лишь выброшенное время.
8. Идеи вычисления минимального количества тестов для куска кода по формальным признакам (например, по количеству условных ветвлений и циклов) — зло. Просто научите программистов тестировать код и научитесь доверять программистам, включая себя (которые в любом случае несут ответственность за их код).
Re[2]: Практика Test-Driven Development
От: Gaperton http://gaperton.livejournal.com
Дата: 20.09.08 22:33
Оценка:
Здравствуйте, LordMAD, Вы писали:

Я далеко не сторонник TDD, но ваши советы нахожу весьма странными. Поясните свою мысль, пожалуйста.

LMA>Тестирование кода должно занимать у программистов не более 25% времени работы над проектом (причем сюда входят все виды тестирования, которые выполняются программистами: unit-тесты, интеграционное тестирование т.д.).


Обоснуйте пожалуйста это утверждение про 25%. Почему не 30. Не 40. Почему не 15.

LMA>3. Не требуйте от себя и от других, чтобы тесты писались в определенные этапы. Например, если Вы хотите, чтобы в момент помещения в VCS тесты уже были, это может привести к тому, что такое правило просто не будет соблюдаться по разным "уважительным" причинам.


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

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


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

LMA>5. Как известно, предварительное написание тестов, позволяет найти проблемы в требованиях на более ранних этапах. Но не забывайте, что этим программист вынужден просто тестировать не свою работу, а работу того, кто отвечает за требования, поэтому может оказаться так, что в то время как один человек экономит 15 минут, целая группа разработчиков будет тратить существенно большее время на написание тестов — очень часто можно найти более эффективные способы проверки требований.


Я правильно вас понял, что вы предлагаете отложить обнаружение самых дорогих ошибок — ошибок в требованиях, на поздние этапы, увеличив их стоимость, только потому, что их типа не программисты допустили, так? Это саботаж в чистом виде.

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


Каким именно образом "дизайн по контракту" может заменить проверки выполнения контрактов тестами?

LMA>7. Есть люди, которым удется хорошо писать тесты, а есть такие у которых баги проходят через тесты как вода сквозь пальцы — такие особенности нужно учитывать (см. деление на то, что надо тестировать и то, что хорошо бы тестировать в п.2): не надо заставлять людей делать ненужную работу — писать плохие тесты — это лишь выброшенное время.


Может быть, вместо отказа от написания тестов, стоит учить людей их правильно писать?

LMA>8. Идеи вычисления минимального количества тестов для куска кода по формальным признакам (например, по количеству условных ветвлений и циклов) — зло. Просто научите программистов тестировать код и научитесь доверять программистам, включая себя (которые в любом случае несут ответственность за их код).


Не вполне понимаю, каким образом вы собираетесь "просто учить людей писать тесты" игнорируя правила white-box тестирования, которые в частности показывают минимально необходимый набор тестов по формальным признакам (анализируя код).
Re[2]: Практика Test-Driven Development
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 21.09.08 06:17
Оценка: 3 (2)
Здравствуйте, LordMAD, Вы писали:

LMA>Тестирование кода должно занимать у программистов не более 25% времени работы над проектом (причем сюда входят все виды тестирования, которые выполняются программистами: unit-тесты, интеграционное тестирование т.д.).

Если вы взяли цифру в 25% из модных книжек по жизненному циклу ПО, то имейте ввиду что там имеется ввиду все тестирование вообще, а не только автоматизированное тестирование. Не заывайте, что отказываясь от какого-либо автоматизированного тестирования вы переносите нагрузку на тестеров (людей), тем самым УВЕЛИЧИВАЕТЕ общее время разработки ПО.

LMA>Это противоречит духу TDD, насколько я понимаю: если Вы пишите тест до кода, гарантировать такого соотношения времени нельзя в сколько-нибудь не тривиальном случае. Однако тестирование — не самоцель, так как тестирование не доказывает отсутствие ошибок и не приводит к улучшению качества кода, как известно (об этом неплохо писал Макконнелл в его Code Complete).

Макконнелл неправ, unit-тестирование очень сильно повышает качество кода, на себе проверил. Интеграционное тестирование таким свойством не обладает.

LMA>Если Вы чувствуете, что тест за малое время написать нельзя:


LMA>2. Разграничьте то, что надо тестировать и то, что хорошо бы тестировать. Тестируйте то, что имеет долгое время жизни (будет использоваться годами, возможно, не в одном проекте). Лучше хорошо протестировать то, что будет использоваться в десятках версий, чем кое-как протестировать и то, что используется часто и то, что перестанет существовать в следующей версии (тех, у кого время "резиновое" — это, конечно, не касается).

Не тестируя какой-либо участок кода вы ничего не экономите. В любом случае его придется тестировать, но уже не автоматически, а вручную.

LMA>Для того, что хорошо бы протестировать обдумайте альтернативные (менее затратные по времени, чем тестирование) варианты: например, можете назначить на code review такого участка кода больше людей (но не переусердствуйте — тут нужно помнить во сколько раз они будут быстрее читать код, чем можно было бы писать тесты для него).

Это такой тонкий эвфемизм для некачественного кода? Качественный код легко поддается тестированию, даже не возникает вопросов писать ли тесты.

LMA>Помните, что существует много способов обнаружения дефектов помимо тестирования — выбирайте самый эффективный из них для каждой конкретной ситуации.

Что может быть быстрее автоматизированного тетсирования?

LMA>3. Не требуйте от себя и от других, чтобы тесты писались в определенные этапы. Например, если Вы хотите, чтобы в момент помещения в VCS тесты уже были, это может привести к тому, что такое правило просто не будет соблюдаться по разным "уважительным" причинам. Особенно хорошо это заметно, когда у программистов свободное расписание — тогда при наличии на рабочем месте тех коллег, которые нужны для обсуждения рабочих вопросов, лучше это время потратить на это, а тесты, как правило, не требуют согласования каких либо вопросов с другими, поэтому их написание можно откладывать на время, когда брифинги и прочие обсуждения не проводятся.

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

LMA>4. TDD предусматривает написание лишь-бы-какого кода для прохождения теста и последующий рефакторинг — но следует помнить, что большинство программистов не любит выбрасывать код, да и современные инструменты рефакторинга далеки от совершенства, так что эти "издержки" TDD надо учитывать.

Откуда эту глупость взяли? При TDD можете писать какой угодно код, вам никто не мешает. Процесс рефакторинга все равно должен привести этот код к самому прстому варианту. Если вы пишете лишь-бы-какой код, неважно для чего — пройти тесты или успеть к дедлайну, то его в любом случае придется выкинуть рано или поздно.

LMA>5. Как известно, предварительное написание тестов, позволяет найти проблемы в требованиях на более ранних этапах. Но не забывайте, что этим программист вынужден просто тестировать не свою работу, а работу того, кто отвечает за требования, поэтому может оказаться так, что в то время как один человек экономит 15 минут, целая группа разработчиков будет тратить существенно большее время на написание тестов — очень часто можно найти более эффективные способы проверки требований.

В требованиях могут быть 2 принципиальные проблемы: неполнота и протеворечивость. В обоих случаях эти проблемы долны быть устранены ДО написания кода (и даже unit-тестов), иначе у вас не получится написать код, удовлетворяющий требованиям. Интеграционные тетсы пишутся когда уже есть код.

LMA>7. Есть люди, которым удется хорошо писать тесты, а есть такие у которых баги проходят через тесты как вода сквозь пальцы — такие особенности нужно учитывать (см. деление на то, что надо тестировать и то, что хорошо бы тестировать в п.2): не надо заставлять людей делать ненужную работу — писать плохие тесты — это лишь выброшенное время.

Значит надо ревьювить тесты с целью повышенияих качества.
Re[3]: Практика Test-Driven Development
От: LordMAD Россия  
Дата: 21.09.08 10:38
Оценка: 5 (2)
Здравствуйте, Gaperton, Вы писали:

G>Я далеко не сторонник TDD, но ваши советы нахожу весьма странными. Поясните свою мысль, пожалуйста.


LMA>>Тестирование кода должно занимать у программистов не более 25% времени работы над проектом (причем сюда входят все виды тестирования, которые выполняются программистами: unit-тесты, интеграционное тестирование т.д.).


G>Обоснуйте пожалуйста это утверждение про 25%. Почему не 30. Не 40. Почему не 15.


Если тестирование + отладка занимает более 50% времени работы на проектом, то это означает, что лучше посадить двух программистов писать независимо одно и тоже, а потом выбрать лучший из двух вариантов, чем писать тесты вообще. Причем, очевидно, отладка занимает больше времени, чем написание тестов, поэтому в самом лучшем для тестирования случае ей достанется 25%.

Ну а еще "максимум 25%" хорошо согласуется с теми исследованиями на эту тему, что мне приходилось видеть. Ссылки на некоторые из них можно найти у того же Макконнелла в Code Complete.

LMA>>3. Не требуйте от себя и от других, чтобы тесты писались в определенные этапы. Например, если Вы хотите, чтобы в момент помещения в VCS тесты уже были, это может привести к тому, что такое правило просто не будет соблюдаться по разным "уважительным" причинам.


G>Еще одна странность. Обоснуйте, почему не надо требовать, чтобы тесты писались в определенные этапы? Объясните, почему не сработает правило "задача не считается закрытой, пока успешно не проходит оговоренный набор юнит-тестов".


Это вопрос того, что считать закрытой задачей. Пока тесты не написаны и не пройдены, считать работу сделанной — нельзя. Но тестирование — это всего лишь тестирование. Оно ничего не гарантирует и оно не является лучшим способом проверки корректности кода (см. на эту тему EWD340 и EWD245.) Я не вижу веских причин не браться за следующую проблему или не отдавать код другим (помещать в VCS), не написав тесты: код и до тестирования и после может содержать ошибки. Естественно, лучше, если до того, как это сделать, написать тесты и пройти их, но если с точки зрения эффективного распределения времени лучше сейчас обсудить следующую проблему с человеком который сейчас доступен или передать код (поместить его в VCS) человеку, который по каким-то причинам ждет этот код, написание тестов вполне можно отложить. Другими словами, члены команды и сами должны понимать, что написание тестов должно быть как можно приближено по времени к написанию тестируемого кода — это просто в их интересах — сделать это, пока они хорошо помнят сам код, но выставлять это в качестве требования — контрпродуктивно.

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


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


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

LMA>>5. Как известно, предварительное написание тестов, позволяет найти проблемы в требованиях на более ранних этапах. Но не забывайте, что этим программист вынужден просто тестировать не свою работу, а работу того, кто отвечает за требования, поэтому может оказаться так, что в то время как один человек экономит 15 минут, целая группа разработчиков будет тратить существенно большее время на написание тестов — очень часто можно найти более эффективные способы проверки требований.


G>Я правильно вас понял, что вы предлагаете отложить обнаружение самых дорогих ошибок — ошибок в требованиях, на поздние этапы, увеличив их стоимость, только потому, что их типа не программисты допустили, так? Это саботаж в чистом виде.


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

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


G>Каким именно образом "дизайн по контракту" может заменить проверки выполнения контрактов тестами?


"Чистые тесты" практически не проверяют контракты, их проверяют как раз "грязные тесты".

LMA>>7. Есть люди, которым удется хорошо писать тесты, а есть такие у которых баги проходят через тесты как вода сквозь пальцы — такие особенности нужно учитывать (см. деление на то, что надо тестировать и то, что хорошо бы тестировать в п.2): не надо заставлять людей делать ненужную работу — писать плохие тесты — это лишь выброшенное время.


G>Может быть, вместо отказа от написания тестов, стоит учить людей их правильно писать?


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

LMA>>8. Идеи вычисления минимального количества тестов для куска кода по формальным признакам (например, по количеству условных ветвлений и циклов) — зло. Просто научите программистов тестировать код и научитесь доверять программистам, включая себя (которые в любом случае несут ответственность за их код).


G>Не вполне понимаю, каким образом вы собираетесь "просто учить людей писать тесты" игнорируя правила white-box тестирования, которые в частности показывают минимально необходимый набор тестов по формальным признакам (анализируя код).


Просто правила для процесса обучения должны отличаться от правил in-the-wild. После обучения человек должен знать эти правила, но нельзя требовать от него соблюдения этих правил всегда и везде. Другими словами, эти правила должны соблюдаться только если они не противоречат здравому смыслу. Например, это касается ситуации, когда по определенным причинам приходится делать более одного ветвления по одному и тому же условию. Необходимость соблюдения неких формальностей в таких случаях может легко привести либо к "высасыванию из пальца", либо к over-дизайну.
Re[3]: Практика Test-Driven Development
От: LordMAD Россия  
Дата: 21.09.08 11:55
Оценка:
Здравствуйте, gandjustas, Вы писали:

G> Не заывайте, что отказываясь от какого-либо автоматизированного тестирования вы переносите нагрузку на тестеров (людей), тем самым УВЕЛИЧИВАЕТЕ общее время разработки ПО.


Процессы ручного тестирования и автоматизированного не зависят друг от друга, они в любом случае дополняют друг друга. А то, что что-то протестировано, например, unit-тестами, не означает, что это не надо тестировать вручную.

LMA>>Это противоречит духу TDD, насколько я понимаю: если Вы пишите тест до кода, гарантировать такого соотношения времени нельзя в сколько-нибудь не тривиальном случае. Однако тестирование — не самоцель, так как тестирование не доказывает отсутствие ошибок и не приводит к улучшению качества кода, как известно (об этом неплохо писал Макконнелл в его Code Complete).

G> Макконнелл неправ, unit-тестирование очень сильно повышает качество кода, на себе проверил. Интеграционное тестирование таким свойством не обладает.

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

LMA>>Если Вы чувствуете, что тест за малое время написать нельзя:


G>Не тестируя какой-либо участок кода вы ничего не экономите. В любом случае его придется тестировать, но уже не автоматически, а вручную.


Вручную тестировать придется в любом случае.

LMA>>Для того, что хорошо бы протестировать обдумайте альтернативные (менее затратные по времени, чем тестирование) варианты: например, можете назначить на code review такого участка кода больше людей (но не переусердствуйте — тут нужно помнить во сколько раз они будут быстрее читать код, чем можно было бы писать тесты для него).

G>Это такой тонкий эвфемизм для некачественного кода? Качественный код легко поддается тестированию, даже не возникает вопросов писать ли тесты.

Речь идет не о простоте написания тестов для кода, речь идет о написании адекватных тестов. Классический пример — нахождение всех ошибок в следующем глючном коде (C++):
int avg(int a, int b) { return (a + b) >> 1; }


LMA>>Помните, что существует много способов обнаружения дефектов помимо тестирования — выбирайте самый эффективный из них для каждой конкретной ситуации.

G>Что может быть быстрее автоматизированного тетсирования?

Много всего. Например, проектирование по контракту.

G>Если не используете TDD, то можете вообще unit-тесты не писать, толку мало от них будет.


Нет. По-моему — настолько очевидно, что даже не вижу необходимости это тут объяснять. Взять хотя бы рефакторинг... Или Вы не видите место рефакторингу вне TDD?

LMA>>4. TDD предусматривает написание лишь-бы-какого кода для прохождения теста и последующий рефакторинг — но следует помнить, что большинство программистов не любит выбрасывать код, да и современные инструменты рефакторинга далеки от совершенства, так что эти "издержки" TDD надо учитывать.

G>Откуда эту глупость взяли? При TDD можете писать какой угодно код, вам никто не мешает. Процесс рефакторинга все равно должен привести этот код к самому прстому варианту. Если вы пишете лишь-бы-какой код, неважно для чего — пройти тесты или успеть к дедлайну, то его в любом случае придется выкинуть рано или поздно.

"Зеленый" этап TDD по Кенту Беку:

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


LMA>>7. Есть люди, которым удется хорошо писать тесты, а есть такие у которых баги проходят через тесты как вода сквозь пальцы — такие особенности нужно учитывать (см. деление на то, что надо тестировать и то, что хорошо бы тестировать в п.2): не надо заставлять людей делать ненужную работу — писать плохие тесты — это лишь выброшенное время.

G>Значит надо ревьювить тесты с целью повышенияих качества.

То, что для тестов надо проводить code review — это очевидный факт. Другое дело — стоит ли заставлять писать тесты тех, у кого это не получается на должно уровне. Проблема не в том, чтобы определить, что тесты плохие, а в том, что конкретный человек может писать отличный код, но не может писать хорошие тесты.
Re[4]: Практика Test-Driven Development
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 21.09.08 13:58
Оценка: 5 (2)
Здравствуйте, LordMAD, Вы писали:

LMA>Здравствуйте, gandjustas, Вы писали:


G>> Не заывайте, что отказываясь от какого-либо автоматизированного тестирования вы переносите нагрузку на тестеров (людей), тем самым УВЕЛИЧИВАЕТЕ общее время разработки ПО.


LMA>Процессы ручного тестирования и автоматизированного не зависят друг от друга, они в любом случае дополняют друг друга. А то, что что-то протестировано, например, unit-тестами, не означает, что это не надо тестировать вручную.

То что тестируется unit-тестами, далеко не всегда может быть протестировано вручную. Не все части рограммы могут работать в собраном приложении изолировано друг от друга.

LMA>>>Это противоречит духу TDD, насколько я понимаю: если Вы пишите тест до кода, гарантировать такого соотношения времени нельзя в сколько-нибудь не тривиальном случае. Однако тестирование — не самоцель, так как тестирование не доказывает отсутствие ошибок и не приводит к улучшению качества кода, как известно (об этом неплохо писал Макконнелл в его Code Complete).

G>> Макконнелл неправ, unit-тестирование очень сильно повышает качество кода, на себе проверил. Интеграционное тестирование таким свойством не обладает.

LMA>В чем конкретно неправ Макконнелл?

Перечитал Макконнелла. Неправльно понял вашу мысль. Тестирование, конечно, не повышает качество кода. А применение TDD сильно повышает.

LMA>По моему опыту лучшее обнаружение дефектов в коде дают: практика написания кода таким образом, чтобы он доказывал свою корректность (что согласуется с тем о чем писали Дейкстра, Степанов, Мейер) инспекции собственного кода, инспекции чужого кода и beta-тестирование (что вполне согласуется с тем, о чем писал Макконнелл).

Писать код чтобы он доказывал свою коррекность? Как это?
Регулярно наблюдаю как люди отлавливают баги в приложении на С++ без тестов. Каждый раз слышу что есть какой-то кусок, который точно работает и в итоге в нем находится ошибка.
Все инспекции проводятся гораздо дольше, чем написание unit-тестов.
beta-тестирование вообще из другой области.

LMA>Другие виды тестирования хороши тем, что позволяют узнать о некоторых дефектах раньше, но речь именно о некоторых дефектах.

Какие?

LMA>>>Если Вы чувствуете, что тест за малое время написать нельзя:

G>>Не тестируя какой-либо участок кода вы ничего не экономите. В любом случае его придется тестировать, но уже не автоматически, а вручную.
LMA>Вручную тестировать придется в любом случае.
Тестируется вручную не часть кода, а часть приложения. Ошибку в таком случае обнаружить гораздо сложнее.

LMA>>>Помните, что существует много способов обнаружения дефектов помимо тестирования — выбирайте самый эффективный из них для каждой конкретной ситуации.

G>>Что может быть быстрее автоматизированного тетсирования?
LMA>Много всего. Например, проектирование по контракту.
Если DbC существует на уровне языка, то возможно. А если нет — все равно надо писать тест.

G>>Если не используете TDD, то можете вообще unit-тесты не писать, толку мало от них будет.

LMA>Нет. По-моему — настолько очевидно, что даже не вижу необходимости это тут объяснять. Взять хотя бы рефакторинг... Или Вы не видите место рефакторингу вне TDD?
Из моего опыта:
а)Писать unit-тесты на сущестующий код сложно (особенно если он написан без оглядки на unit-тестирование), причем тем сложнее, чем больше времени проходит от написания кода до написания тестов.
б)Если тесты написаны после написания кода тестовое покрытие гораздо меньше, чем могло бы быть.
в)Простой рефакторинг возможен и без автоматического тестирования.
г)При малом тестовом покрытии сложный рефакторинг приводит к появлению множества багов.

LMA>>>4. TDD предусматривает написание лишь-бы-какого кода для прохождения теста и последующий рефакторинг — но следует помнить, что большинство программистов не любит выбрасывать код, да и современные инструменты рефакторинга далеки от совершенства, так что эти "издержки" TDD надо учитывать.

G>>Откуда эту глупость взяли? При TDD можете писать какой угодно код, вам никто не мешает. Процесс рефакторинга все равно должен привести этот код к самому прстому варианту. Если вы пишете лишь-бы-какой код, неважно для чего — пройти тесты или успеть к дедлайну, то его в любом случае придется выкинуть рано или поздно.

LMA>"Зеленый" этап TDD по Кенту Беку:

LMA>

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

Да, только после него идет этап рефакторинга. И так по кругу пока не придем к самому простому варианту.
Не надо писать код абы-как, если не рефакторить его в дальнейшем.

LMA>То, что для тестов надо проводить code review — это очевидный факт. Другое дело — стоит ли заставлять писать тесты тех, у кого это не получается на должно уровне. Проблема не в том, чтобы определить, что тесты плохие, а в том, что конкретный человек может писать отличный код, но не может писать хорошие тесты.

Пусть учится.
code review не только способ повышения качества кода, но и средство передачи знаний между разработчиками, применяйте его почаще.
Re[5]: Практика Test-Driven Development
От: LordMAD Россия  
Дата: 21.09.08 15:37
Оценка:
Здравствуйте, gandjustas, Вы писали:

LMA>>По моему опыту лучшее обнаружение дефектов в коде дают: практика написания кода таким образом, чтобы он доказывал свою корректность (что согласуется с тем о чем писали Дейкстра, Степанов, Мейер) инспекции собственного кода, инспекции чужого кода и beta-тестирование (что вполне согласуется с тем, о чем писал Макконнелл).

G>Писать код чтобы он доказывал свою коррекность? Как это?

Это в соответствии с тем, о чем пишут и писали указанные господа. Начинать лучше с Мейера.

LMA>>>>4. TDD предусматривает написание лишь-бы-какого кода для прохождения теста и последующий рефакторинг — но следует помнить, что большинство программистов не любит выбрасывать код, да и современные инструменты рефакторинга далеки от совершенства, так что эти "издержки" TDD надо учитывать.

G>>>Откуда эту глупость взяли? При TDD можете писать какой угодно код, вам никто не мешает. Процесс рефакторинга все равно должен привести этот код к самому прстому варианту. Если вы пишете лишь-бы-какой код, неважно для чего — пройти тесты или успеть к дедлайну, то его в любом случае придется выкинуть рано или поздно.
LMA>>"Зеленый" этап TDD по Кенту Беку:
LMA>>

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

G>Да, только после него идет этап рефакторинга. И так по кругу пока не придем к самому простому варианту.
G>Не надо писать код абы-как, если не рефакторить его в дальнейшем.

Если писать не лишь-бы-какой код для прохождения теста и не выполнять рефакторинг — это уже не TDD.

LMA>>То, что для тестов надо проводить code review — это очевидный факт. Другое дело — стоит ли заставлять писать тесты тех, у кого это не получается на должно уровне. Проблема не в том, чтобы определить, что тесты плохие, а в том, что конкретный человек может писать отличный код, но не может писать хорошие тесты.

G>Пусть учится.

Нет смысла. Пусть лучше делают то, что у них получается делать отлично. Просто нужно учитывать особенности людей при распределении работы.
Re: Практика Test-Driven Development
От: Miroff Россия  
Дата: 21.09.08 18:10
Оценка: 4 (1)
Здравствуйте, 0K, Вы писали:

0K>Что нужно делать дальше? Какие тесты писать?


Если попытаться писать тесты на все приложение разом то получится фигня. Наверняка сам пробовал, если задаешь такой вопрос. Поэтому начнем с того, что разделим приложение на model, view, controller. Для простоты будем считать, то вид это статичные html страницы; методы контроллера пути из URL замаплены на методы контроллера, а модель замаплена на базу. Обращение к сервису оператора и проверки возложим на модель. Можно начинать писать тесты.

1. По запросу http://example.com/mobile-pay/ должна отобразиться страница с формой. Дернем соответствующий метод index контроллера и проверим, вернул ли он форму.

2. Форма отсылает результат на метод по адресу http://example.com/mobile-pay/pay методом POST. Создадим mock модели, который никогда не возвращает ошибок. Проверим, что метод pay вернул сообщение о пополнении баланса, а у модели вызвался метод save.

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

3. Создадим mock объект для сервиса оператора. Это может быть простейший вебервис, возвращающий статичный xml. Аналогично, таких mock'ов нужно два: один всегда отвечает, что номер есть, другой, что номера нет. Проверим, что метод validate модели обращается к mock объекту и возвращает правильный результат.

4. Проверим, что метод validate модели правильно проверяет значение суммы.
5. По вкусу можно проверить поведение в случае отсутствия связи с базой или сервисом оператора.

Все это именно unit тесты, покрывающие весь требуемый функционал. Для того, чтобы стало совсем хорошо нужно написать пару функциональных тестов, проверяющих уже не отдельные части, а весь use-case в сборе.
Re[5]: Практика Test-Driven Development
От: Gaperton http://gaperton.livejournal.com
Дата: 21.09.08 21:22
Оценка:
Здравствуйте, gandjustas, Вы писали:

LMA>>>>Это противоречит духу TDD, насколько я понимаю: если Вы пишите тест до кода, гарантировать такого соотношения времени нельзя в сколько-нибудь не тривиальном случае. Однако тестирование — не самоцель, так как тестирование не доказывает отсутствие ошибок и не приводит к улучшению качества кода, как известно (об этом неплохо писал Макконнелл в его Code Complete).

G>>> Макконнелл неправ, unit-тестирование очень сильно повышает качество кода, на себе проверил. Интеграционное тестирование таким свойством не обладает.

LMA>>В чем конкретно неправ Макконнелл?

G>Перечитал Макконнелла. Неправльно понял вашу мысль. Тестирование, конечно, не повышает качество кода. А применение TDD сильно повышает.

Метрикой "качества кода" является количество ошибок на тысячу строк этого кода. Под "качеством" в управлении проектами понимается количество дефектов, и ничего другое. Утверждение, что тестирование не повашает качества кода — это нонсенс. Даже если приписывать его Макконнеллу. Особенно, если оно идет с присказкой "конечно". Тот показатель, который вы вероятно (я могу только догадываться) имеете в виду под "качеством кода", называется maintainability — он характеризует цену внесения изменений. Это разные вещи. И далеко не всегда и не для всех подсистем целесообразно держать его высоким.
Re[6]: Практика Test-Driven Development
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 22.09.08 03:11
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Здравствуйте, gandjustas, Вы писали:


LMA>>>>>Это противоречит духу TDD, насколько я понимаю: если Вы пишите тест до кода, гарантировать такого соотношения времени нельзя в сколько-нибудь не тривиальном случае. Однако тестирование — не самоцель, так как тестирование не доказывает отсутствие ошибок и не приводит к улучшению качества кода, как известно (об этом неплохо писал Макконнелл в его Code Complete).

G>>>> Макконнелл неправ, unit-тестирование очень сильно повышает качество кода, на себе проверил. Интеграционное тестирование таким свойством не обладает.

LMA>>>В чем конкретно неправ Макконнелл?

G>>Перечитал Макконнелла. Неправльно понял вашу мысль. Тестирование, конечно, не повышает качество кода. А применение TDD сильно повышает.

G>Метрикой "качества кода" является количество ошибок на тысячу строк этого кода. Под "качеством" в управлении проектами понимается количество дефектов, и ничего другое. Утверждение, что тестирование не повашает качества кода — это нонсенс. Даже если приписывать его Макконнеллу. Особенно, если оно идет с присказкой "конечно". Тот показатель, который вы вероятно (я могу только догадываться) имеете в виду под "качеством кода", называется maintainability — он характеризует цену внесения изменений. Это разные вещи. И далеко не всегда и не для всех подсистем целесообразно держать его высоким.


Макконнелл понимает "качество кода" как совокупность факторов, в том числе количество ошибок на тысячу строк и то, что вы называете maintainability.
Но суть не в этом. Макконнелл рассматривает сам факт тестирования программы, говоря что он не увеличивает качество кода. (действительно сколько программу не тестируй работать она будет точно также) Но если рассматривать процесс разработки, в котором автоматизированное тестирование занимает свое место, то при таком процессе качество кода (в любом понимании) возрастает.
Re[4]: Практика Test-Driven Development
От: olegkr  
Дата: 22.09.08 15:47
Оценка:
Здравствуйте, LordMAD, Вы писали:

LMA>Если тестирование + отладка занимает более 50% времени работы на проектом, то это означает, что лучше посадить двух программистов писать независимо одно и тоже, а потом выбрать лучший из двух вариантов, чем писать тесты вообще.

Чем же лучше-то? Программист А сделал багу в классе С1, программист Б в классе С2. И какой из этих вариантов выбрать?
Re[5]: Практика Test-Driven Development
От: LordMAD Россия  
Дата: 22.09.08 17:32
Оценка:
Здравствуйте, olegkr, Вы писали:

LMA>>Если тестирование + отладка занимает более 50% времени работы на проектом, то это означает, что лучше посадить двух программистов писать независимо одно и тоже, а потом выбрать лучший из двух вариантов, чем писать тесты вообще.

O>Чем же лучше-то? Программист А сделал багу в классе С1, программист Б в классе С2. И какой из этих вариантов выбрать?

"Одно и тоже" подразумевают, что они оба будут писать C1.
Re[6]: Практика Test-Driven Development
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 22.09.08 18:19
Оценка:
Здравствуйте, LordMAD, Вы писали:

LMA>Здравствуйте, olegkr, Вы писали:


LMA>>>Если тестирование + отладка занимает более 50% времени работы на проектом, то это означает, что лучше посадить двух программистов писать независимо одно и тоже, а потом выбрать лучший из двух вариантов, чем писать тесты вообще.

O>>Чем же лучше-то? Программист А сделал багу в классе С1, программист Б в классе С2. И какой из этих вариантов выбрать?

LMA>"Одно и тоже" подразумевают, что они оба будут писать C1.

Один сделает в одном методе одну ошибку, другой в этом же методе — другую.
Re[4]: Практика Test-Driven Development
От: Gaperton http://gaperton.livejournal.com
Дата: 22.09.08 21:16
Оценка:
Здравствуйте, LordMAD, Вы писали:

Отличный ответ. Спасибо. У нас намечается интересный разговор. См. комментарии внизу.

LMA>>>Тестирование кода должно занимать у программистов не более 25% времени работы над проектом (причем сюда входят все виды тестирования, которые выполняются программистами: unit-тесты, интеграционное тестирование т.д.).


G>>Обоснуйте пожалуйста это утверждение про 25%. Почему не 30. Не 40. Почему не 15.


LMA>Если тестирование + отладка занимает более 50% времени работы на проектом, то это означает, что лучше посадить двух программистов писать независимо одно и тоже, а потом выбрать лучший из двух вариантов, чем писать тесты вообще. Причем, очевидно, отладка занимает больше времени, чем написание тестов, поэтому в самом лучшем для тестирования случае ей достанется 25%.


Гхм. Обоснование элегантное, спору нет, я ценю его красоту . Однако продолжим его.

Пусть программисты А (делают в среднем по 20 ошибок на 1000 строк кода) и Б (делает в среднем по 30 ошибок на 1000) строк кода, которые вылавливаются тестами. Вполне реальные цифры, кстати — этот коридор колеблется от 20 до 40, и метрика "плотность ошибок" очень стабильна для каждого отдельного программиста. Данные — из исследований мистера Хамфри по PSP/TSP (это автор CMMI).

Пусть они пишут подсистему размером в 1000 строк, и у нас высокие требования к качеству. Скажем, это медицинская система какия-нибудь.

Мы, зная, что на тестирование-отладку у нас уходит 50% времени, поручаем ее обоим программистам. Получаем две системы с разным detailed design, в одной из которых примерно 20 ошибок, в другой — примерно 30. Что мы делаем дальше?

Что рекомендует повернутая на проблеме качества теория и методология PSP/TSP, и как именно это соотносится с вашей дискуссией по TDD, я раскажу позднее. Пока мне любопытен ваш ответ. Вдруг я чего-то не понимаю, и вы меня озадачите? Нельзя такое сбрасывать со счетов, даже если знаком с PSP/TSP, случаи разные бывают.

LMA>Ну а еще "максимум 25%" хорошо согласуется с теми исследованиями на эту тему, что мне приходилось видеть. Ссылки на некоторые из них можно найти у того же Макконнелла в Code Complete.


Отлично. Допустим для целей нашей дискуссии, что это так и есть (цифра, кстати, на мой взгляд вполне правдоподобная). Теперь вопрос. У вас по замерам времени выяснилось, что это время — 40%. Вы — менеджер. У вас группа из 6 человек программистов. Ваши действия? Что лично вы делать будете? Каков будет план ваших мероприятий? В терминах конкретных действий, если можно.

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

На следующую половину поста отвечу другим своим постом. Спасибо.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.