TDD и вообще юнит-тесты in the wild

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
77 messages Options
1234
Reply | Threaded
Open this post in threaded view
|

Re: TDD и вообще юнит-тесты in the wild

Dennis Schetinin
Я таки бегло глянул формат, и мне показалось, что worksheet-ы идут в один файл. Если это не так, изменения тривиальны, если вообще не сводятся к изменению названия одного символа…
В общем, получается примерно так:

OdsExporeterTests >> testGeneratesSubDocuments
  | exporter actualResult |  
  
  exporter := OdsExporter new.

  [ :contentGenerator :styleGenerator :rootGenerator :zipper |

    exporter
      contentGenerator: contentGenertor;
      styleGenerator: styleGenerator;
      rootGenerator: rootGenerator;
      zipper: zipper.

    [actualResult := exporter generate: #worksheets with: #style] 
        should strictly satisfy: 
    [ (contentGenerator generate: #worksheets) willReturn: #contentsFile.
      (styleGenerator generate: #style) willReturn: #styleFile.
      (rootGenerator generateContent: #contentsFile withStyle: #styleFile) willReturn: #rootFile.
      (zipper zip:(Set with: #rootFile with: #contentFile with: #styleFile)) willReturn: #odsFile ]
  
  ] runScenario.
  
  actualResult should be: #odsFile.



Название теста не очень удачное, но пока сойдет — по необходимости потом можно поменять.


--

Best regards,


Dennis Schetinin


2 декабря 2014 г., 12:54 пользователь Юрий Мироненко <[hidden email]> написал:
Ну, чтобы было общее понимание: нужно сформировать не одну, а несколько XMLек.

По одной на каждый worksheet (этот worksheet по общим идеям будет напоминать HTMLную таблицу), одну на workbook, одну на таблицу стилей и ещё одну - на файл с описанием того, какая из остальных XMLек воркбук, какая - воркщит(ы), какая - таблица стилей и где они все лежат (потому что они не обязаны лежать в корне документа). И всё это зазиповать.

Это в простейшем случае. В более сложном там могут быть, например, ещё и картинки. Но мы пока не будем так извращаться.

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

2 декабря 2014 г., 11:36 пользователь Dennis Schetinin <[hidden email]> написал:

Здесь для самого себя надо отделить что "мы тестируем быстро и модульно” и что "мы тестируем долго и полностью”.
Я бы для быстрых тестов не стал бы создавать workbook с worksheet-ами, потому как тестирование даже экспорта пустого документа - это значит тестировать работу в кооперации нескольких классов. Штук пяти не меньше.
Это не модульные тесты. 

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

Прямо сейчас не могу как следует заняться этим примером (он выглядит гораздо интереснее, чем казалось сначала). Постараюсь в ближайшее время найти возможность для этого. Было бы замечательно, если бы устройство ODS кто-ниубудь описал точнее. (Я,действительно, думал там надо просто сформировать XML). Или можем взять за основу то, что написано (независимо от правильности) — для исследования TDD это не важно. Но на изучение формата ODS у меня точно не хватит ни времени, ни сил :)


--

Best regards,


Dennis Schetinin


2 декабря 2014 г., 3:55 пользователь Vladimir Musulainen <[hidden email]> написал:

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


Здесь для самого себя надо отделить что "мы тестируем быстро и модульно” и что "мы тестируем долго и полностью”.

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

Я приведу процесс создания xlsx (по памяти, могу соврать)
1. Создание xml c данными
2. Создание файлов связей
3. Упаковка всего в архив

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

Например, архивирование просится в отдельный класс. На этот класс и пишутся тесты. На входе пачка файлов (или директория) - на выходе архив с заданным именем.
Создание XML тоже отдельная задача.
Пытаться тестировать сразу все - распространенная ошибка. Модульное тестирование проверяет работу маленьких кирпичиков. Приемочное тестирование уже работе механизма в целом или его частей, если механизм достаточно велик. А вот в приемных тестах выбирать разработчику будут ли он это автоматизировать и проводить тесты вручную. Если будет автоматизировать - не обойтись без соответствующего окружения для чтения xlsx. Можно и не парить  xlsx, а открывать через COM  файл EXCEL и запрашивать значения ячеек сверяя с эталонным. Работа с COM медленная и запускать такие тесты накладно каждый десять минут. Поэтому их можно отделить в пачку тестов которые запускается перед мержем бренча разработки в основной бранч (master).

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

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




--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: TDD и вообще юнит-тесты in the wild

Dennis Schetinin
Все так плохо? :)


--

Best regards,


Dennis Schetinin


2 декабря 2014 г., 15:01 пользователь Dennis Schetinin <[hidden email]> написал:
Я таки бегло глянул формат, и мне показалось, что worksheet-ы идут в один файл. Если это не так, изменения тривиальны, если вообще не сводятся к изменению названия одного символа…
В общем, получается примерно так:

OdsExporeterTests >> testGeneratesSubDocuments
  | exporter actualResult |  
  
  exporter := OdsExporter new.

  [ :contentGenerator :styleGenerator :rootGenerator :zipper |

    exporter
      contentGenerator: contentGenertor;
      styleGenerator: styleGenerator;
      rootGenerator: rootGenerator;
      zipper: zipper.

    [actualResult := exporter generate: #worksheets with: #style] 
        should strictly satisfy: 
    [ (contentGenerator generate: #worksheets) willReturn: #contentsFile.
      (styleGenerator generate: #style) willReturn: #styleFile.
      (rootGenerator generateContent: #contentsFile withStyle: #styleFile) willReturn: #rootFile.
      (zipper zip:(Set with: #rootFile with: #contentFile with: #styleFile)) willReturn: #odsFile ]
  
  ] runScenario.
  
  actualResult should be: #odsFile.



Название теста не очень удачное, но пока сойдет — по необходимости потом можно поменять.


--

Best regards,


Dennis Schetinin


2 декабря 2014 г., 12:54 пользователь Юрий Мироненко <[hidden email]> написал:

Ну, чтобы было общее понимание: нужно сформировать не одну, а несколько XMLек.

По одной на каждый worksheet (этот worksheet по общим идеям будет напоминать HTMLную таблицу), одну на workbook, одну на таблицу стилей и ещё одну - на файл с описанием того, какая из остальных XMLек воркбук, какая - воркщит(ы), какая - таблица стилей и где они все лежат (потому что они не обязаны лежать в корне документа). И всё это зазиповать.

Это в простейшем случае. В более сложном там могут быть, например, ещё и картинки. Но мы пока не будем так извращаться.

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

2 декабря 2014 г., 11:36 пользователь Dennis Schetinin <[hidden email]> написал:

Здесь для самого себя надо отделить что "мы тестируем быстро и модульно” и что "мы тестируем долго и полностью”.
Я бы для быстрых тестов не стал бы создавать workbook с worksheet-ами, потому как тестирование даже экспорта пустого документа - это значит тестировать работу в кооперации нескольких классов. Штук пяти не меньше.
Это не модульные тесты. 

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

Прямо сейчас не могу как следует заняться этим примером (он выглядит гораздо интереснее, чем казалось сначала). Постараюсь в ближайшее время найти возможность для этого. Было бы замечательно, если бы устройство ODS кто-ниубудь описал точнее. (Я,действительно, думал там надо просто сформировать XML). Или можем взять за основу то, что написано (независимо от правильности) — для исследования TDD это не важно. Но на изучение формата ODS у меня точно не хватит ни времени, ни сил :)


--

Best regards,


Dennis Schetinin


2 декабря 2014 г., 3:55 пользователь Vladimir Musulainen <[hidden email]> написал:

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


Здесь для самого себя надо отделить что "мы тестируем быстро и модульно” и что "мы тестируем долго и полностью”.

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

Я приведу процесс создания xlsx (по памяти, могу соврать)
1. Создание xml c данными
2. Создание файлов связей
3. Упаковка всего в архив

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

Например, архивирование просится в отдельный класс. На этот класс и пишутся тесты. На входе пачка файлов (или директория) - на выходе архив с заданным именем.
Создание XML тоже отдельная задача.
Пытаться тестировать сразу все - распространенная ошибка. Модульное тестирование проверяет работу маленьких кирпичиков. Приемочное тестирование уже работе механизма в целом или его частей, если механизм достаточно велик. А вот в приемных тестах выбирать разработчику будут ли он это автоматизировать и проводить тесты вручную. Если будет автоматизировать - не обойтись без соответствующего окружения для чтения xlsx. Можно и не парить  xlsx, а открывать через COM  файл EXCEL и запрашивать значения ячеек сверяя с эталонным. Работа с COM медленная и запускать такие тесты накладно каждый десять минут. Поэтому их можно отделить в пачку тестов которые запускается перед мержем бренча разработки в основной бранч (master).

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

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




--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.


--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: TDD и вообще юнит-тесты in the wild

Yuriy Mironenko
Все так плохо? :)

А? Просто немного зашиваюсь что-то.
Не доходят руки. Если речь вообще о том, о чём я подумал.

4 декабря 2014 г., 15:50 пользователь Dennis Schetinin <[hidden email]> написал:
Все так плохо? :)


--

Best regards,


Dennis Schetinin


2 декабря 2014 г., 15:01 пользователь Dennis Schetinin <[hidden email]> написал:

Я таки бегло глянул формат, и мне показалось, что worksheet-ы идут в один файл. Если это не так, изменения тривиальны, если вообще не сводятся к изменению названия одного символа…
В общем, получается примерно так:

OdsExporeterTests >> testGeneratesSubDocuments
  | exporter actualResult |  
  
  exporter := OdsExporter new.

  [ :contentGenerator :styleGenerator :rootGenerator :zipper |

    exporter
      contentGenerator: contentGenertor;
      styleGenerator: styleGenerator;
      rootGenerator: rootGenerator;
      zipper: zipper.

    [actualResult := exporter generate: #worksheets with: #style] 
        should strictly satisfy: 
    [ (contentGenerator generate: #worksheets) willReturn: #contentsFile.
      (styleGenerator generate: #style) willReturn: #styleFile.
      (rootGenerator generateContent: #contentsFile withStyle: #styleFile) willReturn: #rootFile.
      (zipper zip:(Set with: #rootFile with: #contentFile with: #styleFile)) willReturn: #odsFile ]
  
  ] runScenario.
  
  actualResult should be: #odsFile.



Название теста не очень удачное, но пока сойдет — по необходимости потом можно поменять.


--

Best regards,


Dennis Schetinin


2 декабря 2014 г., 12:54 пользователь Юрий Мироненко <[hidden email]> написал:

Ну, чтобы было общее понимание: нужно сформировать не одну, а несколько XMLек.

По одной на каждый worksheet (этот worksheet по общим идеям будет напоминать HTMLную таблицу), одну на workbook, одну на таблицу стилей и ещё одну - на файл с описанием того, какая из остальных XMLек воркбук, какая - воркщит(ы), какая - таблица стилей и где они все лежат (потому что они не обязаны лежать в корне документа). И всё это зазиповать.

Это в простейшем случае. В более сложном там могут быть, например, ещё и картинки. Но мы пока не будем так извращаться.

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

2 декабря 2014 г., 11:36 пользователь Dennis Schetinin <[hidden email]> написал:

Здесь для самого себя надо отделить что "мы тестируем быстро и модульно” и что "мы тестируем долго и полностью”.
Я бы для быстрых тестов не стал бы создавать workbook с worksheet-ами, потому как тестирование даже экспорта пустого документа - это значит тестировать работу в кооперации нескольких классов. Штук пяти не меньше.
Это не модульные тесты. 

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

Прямо сейчас не могу как следует заняться этим примером (он выглядит гораздо интереснее, чем казалось сначала). Постараюсь в ближайшее время найти возможность для этого. Было бы замечательно, если бы устройство ODS кто-ниубудь описал точнее. (Я,действительно, думал там надо просто сформировать XML). Или можем взять за основу то, что написано (независимо от правильности) — для исследования TDD это не важно. Но на изучение формата ODS у меня точно не хватит ни времени, ни сил :)


--

Best regards,


Dennis Schetinin


2 декабря 2014 г., 3:55 пользователь Vladimir Musulainen <[hidden email]> написал:

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


Здесь для самого себя надо отделить что "мы тестируем быстро и модульно” и что "мы тестируем долго и полностью”.

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

Я приведу процесс создания xlsx (по памяти, могу соврать)
1. Создание xml c данными
2. Создание файлов связей
3. Упаковка всего в архив

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

Например, архивирование просится в отдельный класс. На этот класс и пишутся тесты. На входе пачка файлов (или директория) - на выходе архив с заданным именем.
Создание XML тоже отдельная задача.
Пытаться тестировать сразу все - распространенная ошибка. Модульное тестирование проверяет работу маленьких кирпичиков. Приемочное тестирование уже работе механизма в целом или его частей, если механизм достаточно велик. А вот в приемных тестах выбирать разработчику будут ли он это автоматизировать и проводить тесты вручную. Если будет автоматизировать - не обойтись без соответствующего окружения для чтения xlsx. Можно и не парить  xlsx, а открывать через COM  файл EXCEL и запрашивать значения ячеек сверяя с эталонным. Работа с COM медленная и запускать такие тесты накладно каждый десять минут. Поэтому их можно отделить в пачку тестов которые запускается перед мержем бренча разработки в основной бранч (master).

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

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




--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.


--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: TDD и вообще юнит-тесты in the wild

Dennis Schetinin
Я про наши экзерсисы с TDD :)
… Если к крайнему примеру нужны пояснения, я готов их дать. Может быть, это просто совпадение, но почему-то примерно на этой стадии нередко все заканчивается. Возникает ощущение, что тесты с моками отбивают всякое желание продолжать. Хотя, на самом деле все довольно просто.


--

Best regards,


Dennis Schetinin


7 декабря 2014 г., 17:09 пользователь Юрий Мироненко <[hidden email]> написал:
Все так плохо? :)

А? Просто немного зашиваюсь что-то.
Не доходят руки. Если речь вообще о том, о чём я подумал.

4 декабря 2014 г., 15:50 пользователь Dennis Schetinin <[hidden email]> написал:

Все так плохо? :)


--

Best regards,


Dennis Schetinin


2 декабря 2014 г., 15:01 пользователь Dennis Schetinin <[hidden email]> написал:

Я таки бегло глянул формат, и мне показалось, что worksheet-ы идут в один файл. Если это не так, изменения тривиальны, если вообще не сводятся к изменению названия одного символа…
В общем, получается примерно так:

OdsExporeterTests >> testGeneratesSubDocuments
  | exporter actualResult |  
  
  exporter := OdsExporter new.

  [ :contentGenerator :styleGenerator :rootGenerator :zipper |

    exporter
      contentGenerator: contentGenertor;
      styleGenerator: styleGenerator;
      rootGenerator: rootGenerator;
      zipper: zipper.

    [actualResult := exporter generate: #worksheets with: #style] 
        should strictly satisfy: 
    [ (contentGenerator generate: #worksheets) willReturn: #contentsFile.
      (styleGenerator generate: #style) willReturn: #styleFile.
      (rootGenerator generateContent: #contentsFile withStyle: #styleFile) willReturn: #rootFile.
      (zipper zip:(Set with: #rootFile with: #contentFile with: #styleFile)) willReturn: #odsFile ]
  
  ] runScenario.
  
  actualResult should be: #odsFile.



Название теста не очень удачное, но пока сойдет — по необходимости потом можно поменять.


--

Best regards,


Dennis Schetinin


2 декабря 2014 г., 12:54 пользователь Юрий Мироненко <[hidden email]> написал:

Ну, чтобы было общее понимание: нужно сформировать не одну, а несколько XMLек.

По одной на каждый worksheet (этот worksheet по общим идеям будет напоминать HTMLную таблицу), одну на workbook, одну на таблицу стилей и ещё одну - на файл с описанием того, какая из остальных XMLек воркбук, какая - воркщит(ы), какая - таблица стилей и где они все лежат (потому что они не обязаны лежать в корне документа). И всё это зазиповать.

Это в простейшем случае. В более сложном там могут быть, например, ещё и картинки. Но мы пока не будем так извращаться.

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

2 декабря 2014 г., 11:36 пользователь Dennis Schetinin <[hidden email]> написал:

Здесь для самого себя надо отделить что "мы тестируем быстро и модульно” и что "мы тестируем долго и полностью”.
Я бы для быстрых тестов не стал бы создавать workbook с worksheet-ами, потому как тестирование даже экспорта пустого документа - это значит тестировать работу в кооперации нескольких классов. Штук пяти не меньше.
Это не модульные тесты. 

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

Прямо сейчас не могу как следует заняться этим примером (он выглядит гораздо интереснее, чем казалось сначала). Постараюсь в ближайшее время найти возможность для этого. Было бы замечательно, если бы устройство ODS кто-ниубудь описал точнее. (Я,действительно, думал там надо просто сформировать XML). Или можем взять за основу то, что написано (независимо от правильности) — для исследования TDD это не важно. Но на изучение формата ODS у меня точно не хватит ни времени, ни сил :)


--

Best regards,


Dennis Schetinin


2 декабря 2014 г., 3:55 пользователь Vladimir Musulainen <[hidden email]> написал:

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


Здесь для самого себя надо отделить что "мы тестируем быстро и модульно” и что "мы тестируем долго и полностью”.

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

Я приведу процесс создания xlsx (по памяти, могу соврать)
1. Создание xml c данными
2. Создание файлов связей
3. Упаковка всего в архив

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

Например, архивирование просится в отдельный класс. На этот класс и пишутся тесты. На входе пачка файлов (или директория) - на выходе архив с заданным именем.
Создание XML тоже отдельная задача.
Пытаться тестировать сразу все - распространенная ошибка. Модульное тестирование проверяет работу маленьких кирпичиков. Приемочное тестирование уже работе механизма в целом или его частей, если механизм достаточно велик. А вот в приемных тестах выбирать разработчику будут ли он это автоматизировать и проводить тесты вручную. Если будет автоматизировать - не обойтись без соответствующего окружения для чтения xlsx. Можно и не парить  xlsx, а открывать через COM  файл EXCEL и запрашивать значения ячеек сверяя с эталонным. Работа с COM медленная и запускать такие тесты накладно каждый десять минут. Поэтому их можно отделить в пачку тестов которые запускается перед мержем бренча разработки в основной бранч (master).

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

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




--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.


--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: TDD и вообще юнит-тесты in the wild

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

#runScenario и т.п.

Что за пакет-то?

8 декабря 2014 г., 8:27 пользователь Dennis Schetinin <[hidden email]> написал:
Я про наши экзерсисы с TDD :)
… Если к крайнему примеру нужны пояснения, я готов их дать. Может быть, это просто совпадение, но почему-то примерно на этой стадии нередко все заканчивается. Возникает ощущение, что тесты с моками отбивают всякое желание продолжать. Хотя, на самом деле все довольно просто.


--

Best regards,


Dennis Schetinin


7 декабря 2014 г., 17:09 пользователь Юрий Мироненко <[hidden email]> написал:

Все так плохо? :)

А? Просто немного зашиваюсь что-то.
Не доходят руки. Если речь вообще о том, о чём я подумал.

4 декабря 2014 г., 15:50 пользователь Dennis Schetinin <[hidden email]> написал:

Все так плохо? :)


--

Best regards,


Dennis Schetinin


2 декабря 2014 г., 15:01 пользователь Dennis Schetinin <[hidden email]> написал:

Я таки бегло глянул формат, и мне показалось, что worksheet-ы идут в один файл. Если это не так, изменения тривиальны, если вообще не сводятся к изменению названия одного символа…
В общем, получается примерно так:

OdsExporeterTests >> testGeneratesSubDocuments
  | exporter actualResult |  
  
  exporter := OdsExporter new.

  [ :contentGenerator :styleGenerator :rootGenerator :zipper |

    exporter
      contentGenerator: contentGenertor;
      styleGenerator: styleGenerator;
      rootGenerator: rootGenerator;
      zipper: zipper.

    [actualResult := exporter generate: #worksheets with: #style] 
        should strictly satisfy: 
    [ (contentGenerator generate: #worksheets) willReturn: #contentsFile.
      (styleGenerator generate: #style) willReturn: #styleFile.
      (rootGenerator generateContent: #contentsFile withStyle: #styleFile) willReturn: #rootFile.
      (zipper zip:(Set with: #rootFile with: #contentFile with: #styleFile)) willReturn: #odsFile ]
  
  ] runScenario.
  
  actualResult should be: #odsFile.



Название теста не очень удачное, но пока сойдет — по необходимости потом можно поменять.


--

Best regards,


Dennis Schetinin


2 декабря 2014 г., 12:54 пользователь Юрий Мироненко <[hidden email]> написал:

Ну, чтобы было общее понимание: нужно сформировать не одну, а несколько XMLек.

По одной на каждый worksheet (этот worksheet по общим идеям будет напоминать HTMLную таблицу), одну на workbook, одну на таблицу стилей и ещё одну - на файл с описанием того, какая из остальных XMLек воркбук, какая - воркщит(ы), какая - таблица стилей и где они все лежат (потому что они не обязаны лежать в корне документа). И всё это зазиповать.

Это в простейшем случае. В более сложном там могут быть, например, ещё и картинки. Но мы пока не будем так извращаться.

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

2 декабря 2014 г., 11:36 пользователь Dennis Schetinin <[hidden email]> написал:

Здесь для самого себя надо отделить что "мы тестируем быстро и модульно” и что "мы тестируем долго и полностью”.
Я бы для быстрых тестов не стал бы создавать workbook с worksheet-ами, потому как тестирование даже экспорта пустого документа - это значит тестировать работу в кооперации нескольких классов. Штук пяти не меньше.
Это не модульные тесты. 

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

Прямо сейчас не могу как следует заняться этим примером (он выглядит гораздо интереснее, чем казалось сначала). Постараюсь в ближайшее время найти возможность для этого. Было бы замечательно, если бы устройство ODS кто-ниубудь описал точнее. (Я,действительно, думал там надо просто сформировать XML). Или можем взять за основу то, что написано (независимо от правильности) — для исследования TDD это не важно. Но на изучение формата ODS у меня точно не хватит ни времени, ни сил :)


--

Best regards,


Dennis Schetinin


2 декабря 2014 г., 3:55 пользователь Vladimir Musulainen <[hidden email]> написал:

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


Здесь для самого себя надо отделить что "мы тестируем быстро и модульно” и что "мы тестируем долго и полностью”.

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

Я приведу процесс создания xlsx (по памяти, могу соврать)
1. Создание xml c данными
2. Создание файлов связей
3. Упаковка всего в архив

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

Например, архивирование просится в отдельный класс. На этот класс и пишутся тесты. На входе пачка файлов (или директория) - на выходе архив с заданным именем.
Создание XML тоже отдельная задача.
Пытаться тестировать сразу все - распространенная ошибка. Модульное тестирование проверяет работу маленьких кирпичиков. Приемочное тестирование уже работе механизма в целом или его частей, если механизм достаточно велик. А вот в приемных тестах выбирать разработчику будут ли он это автоматизировать и проводить тесты вручную. Если будет автоматизировать - не обойтись без соответствующего окружения для чтения xlsx. Можно и не парить  xlsx, а открывать через COM  файл EXCEL и запрашивать значения ячеек сверяя с эталонным. Работа с COM медленная и запускать такие тесты накладно каждый десять минут. Поэтому их можно отделить в пачку тестов которые запускается перед мержем бренча разработки в основной бранч (master).

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

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




--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.


--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: TDD и вообще юнит-тесты in the wild

Dennis Schetinin
Mocketry [http://www.smalltalkhub.com/#!/~dionisiy/Mocketry], конечно! :) Автор присутствует здесь, ежели чо… На мой взгляд, там все читается как обычный английский. Если это не так — готов подробно прокомментировать. Сейчас скажу, что параметры блока сценария (:contentGenerator :styleGenerator :rootGenerator :zipper) превращаются в моки.


--

Best regards,


Dennis Schetinin


8 декабря 2014 г., 14:56 пользователь Юрий Мироненко <[hidden email]> написал:
Ну на самом деле тут скорее приближающийся конец года...но, тем не менее, даже беглый взгляд подсказывает, что там используется какой-то пакет для этих самых моков.

#runScenario и т.п.

Что за пакет-то?

8 декабря 2014 г., 8:27 пользователь Dennis Schetinin <[hidden email]> написал:

Я про наши экзерсисы с TDD :)
… Если к крайнему примеру нужны пояснения, я готов их дать. Может быть, это просто совпадение, но почему-то примерно на этой стадии нередко все заканчивается. Возникает ощущение, что тесты с моками отбивают всякое желание продолжать. Хотя, на самом деле все довольно просто.


--

Best regards,


Dennis Schetinin


7 декабря 2014 г., 17:09 пользователь Юрий Мироненко <[hidden email]> написал:

Все так плохо? :)

А? Просто немного зашиваюсь что-то.
Не доходят руки. Если речь вообще о том, о чём я подумал.

4 декабря 2014 г., 15:50 пользователь Dennis Schetinin <[hidden email]> написал:

Все так плохо? :)


--

Best regards,


Dennis Schetinin


2 декабря 2014 г., 15:01 пользователь Dennis Schetinin <[hidden email]> написал:

Я таки бегло глянул формат, и мне показалось, что worksheet-ы идут в один файл. Если это не так, изменения тривиальны, если вообще не сводятся к изменению названия одного символа…
В общем, получается примерно так:

OdsExporeterTests >> testGeneratesSubDocuments
  | exporter actualResult |  
  
  exporter := OdsExporter new.

  [ :contentGenerator :styleGenerator :rootGenerator :zipper |

    exporter
      contentGenerator: contentGenertor;
      styleGenerator: styleGenerator;
      rootGenerator: rootGenerator;
      zipper: zipper.

    [actualResult := exporter generate: #worksheets with: #style] 
        should strictly satisfy: 
    [ (contentGenerator generate: #worksheets) willReturn: #contentsFile.
      (styleGenerator generate: #style) willReturn: #styleFile.
      (rootGenerator generateContent: #contentsFile withStyle: #styleFile) willReturn: #rootFile.
      (zipper zip:(Set with: #rootFile with: #contentFile with: #styleFile)) willReturn: #odsFile ]
  
  ] runScenario.
  
  actualResult should be: #odsFile.



Название теста не очень удачное, но пока сойдет — по необходимости потом можно поменять.


--

Best regards,


Dennis Schetinin


2 декабря 2014 г., 12:54 пользователь Юрий Мироненко <[hidden email]> написал:

Ну, чтобы было общее понимание: нужно сформировать не одну, а несколько XMLек.

По одной на каждый worksheet (этот worksheet по общим идеям будет напоминать HTMLную таблицу), одну на workbook, одну на таблицу стилей и ещё одну - на файл с описанием того, какая из остальных XMLек воркбук, какая - воркщит(ы), какая - таблица стилей и где они все лежат (потому что они не обязаны лежать в корне документа). И всё это зазиповать.

Это в простейшем случае. В более сложном там могут быть, например, ещё и картинки. Но мы пока не будем так извращаться.

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

2 декабря 2014 г., 11:36 пользователь Dennis Schetinin <[hidden email]> написал:

Здесь для самого себя надо отделить что "мы тестируем быстро и модульно” и что "мы тестируем долго и полностью”.
Я бы для быстрых тестов не стал бы создавать workbook с worksheet-ами, потому как тестирование даже экспорта пустого документа - это значит тестировать работу в кооперации нескольких классов. Штук пяти не меньше.
Это не модульные тесты. 

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

Прямо сейчас не могу как следует заняться этим примером (он выглядит гораздо интереснее, чем казалось сначала). Постараюсь в ближайшее время найти возможность для этого. Было бы замечательно, если бы устройство ODS кто-ниубудь описал точнее. (Я,действительно, думал там надо просто сформировать XML). Или можем взять за основу то, что написано (независимо от правильности) — для исследования TDD это не важно. Но на изучение формата ODS у меня точно не хватит ни времени, ни сил :)


--

Best regards,


Dennis Schetinin


2 декабря 2014 г., 3:55 пользователь Vladimir Musulainen <[hidden email]> написал:

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


Здесь для самого себя надо отделить что "мы тестируем быстро и модульно” и что "мы тестируем долго и полностью”.

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

Я приведу процесс создания xlsx (по памяти, могу соврать)
1. Создание xml c данными
2. Создание файлов связей
3. Упаковка всего в архив

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

Например, архивирование просится в отдельный класс. На этот класс и пишутся тесты. На входе пачка файлов (или директория) - на выходе архив с заданным именем.
Создание XML тоже отдельная задача.
Пытаться тестировать сразу все - распространенная ошибка. Модульное тестирование проверяет работу маленьких кирпичиков. Приемочное тестирование уже работе механизма в целом или его частей, если механизм достаточно велик. А вот в приемных тестах выбирать разработчику будут ли он это автоматизировать и проводить тесты вручную. Если будет автоматизировать - не обойтись без соответствующего окружения для чтения xlsx. Можно и не парить  xlsx, а открывать через COM  файл EXCEL и запрашивать значения ячеек сверяя с эталонным. Работа с COM медленная и запускать такие тесты накладно каждый десять минут. Поэтому их можно отделить в пачку тестов которые запускается перед мержем бренча разработки в основной бранч (master).

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

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




--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.


--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: TDD и вообще юнит-тесты in the wild

Genosse


понедельник, 8 декабря 2014 г., 22:19:21 UTC+4 пользователь chaetal написал:
 Если это не так — готов подробно прокомментировать.

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

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: TDD и вообще юнит-тесты in the wild

Dennis Schetinin
Начинаем с чистого листа разработку систему экспорта таблиц в ODS формат. Что мы хотим получить? Некий объект, который умеет "генерить" ODS-файлы:

OdsExporeterTests >> testGenerates
  exporter generate should be: #someOdsFile

Я пока не знаю, что такое ODS-файл, так что использую самую простую заглушку (в виде символа). Но надо понять, откуда берется этот самый ODS-файл? В соответствии с документацией, это результат зипования нескольких файлов, а именно контента, стиля (могут быть еще, но эти два, как я понял, обязательны) и файла с общим описанием — корневого файла. Следовательно в процессе генерации мне понадобится объект, который будет зиповать, и он должен получить соответствующее сообщение с перечнем зипуемых файлов; то, что он вернет в ответ на это сообщение и будет результирующим ODS-файлом:

OdsExporeterTests >> testGenerates
  
  [actualResult := exporter generate] should strictly satisfy: 
        [
        (zipper zip:(Set with: #rootFile with: #contentFile with: #styleFile)) 
            willReturn: #odsFile
        ]

  actualResult should be: #odsFile



===== Отступление =====

Добавленная структура имеет вид:

block1 should strictly satisfy: block2.

Возможность сказать системе, что в процессе выполнения некоторых действий (первый блок) должны быть выполнены следующие действия (второй блок) — как раз и обеспечивает нам Mocketry (или любой другой фреймворк, реализующий mock objects). Собственно, мок — это объект, который создается внутри теста и сначала сохраняет ("записывает") полученные сообщения как "ожидания", а затем — в процессе выполнения теста — проверяет, что ожидания действительно были выполнены:

[systemUnderTest exerciseMessage] should strictly satisfy: [mock someMessage].

Фреймворк сначала включит стадию "записи", в ходе которой выполнит второй блок, отследит получение объектом mock сообщения #someMessage и запомнит это как "ожидание". Затем фреймворк перейдет на стадию "воспроизведения" и выполнит первый блок. Если в процессе ее выполнения mock получить сообщение #someMessage, то ожидание будет помечено как выполненное. Если мок получает неожиданное сообщение, то тест проваливается. Если не все ожидания выполнены, то тест проваливается. 

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

[actualResult := systemUnderTest exerciseMessage] should strictly satisfy: 
    [mock someMessage willReturn: #expectedResult].

Когда объект mock получит сообщение #someMessage, будет возвращено #expectedResult в качестве ответа. И, к примеру, проверка типа

actualResult should be: #expectedResult

будет успешно выполнена.

Mocketry использует концепцию "сценария" чтобы… создать что-то вроде среды для выполнения теста с моками… (Денис Кудряшов, наверное, лучше объяснит этот момент, но она нужна. :)  Эта самая среда создается "внутри" блока, если ему послать сообщение #runScenario. То есть, типичный тест с моками выглядит так:

[ :mock1 :mock2 |
  exerciseBlock should satisfy: expectationsBlock
] runScenario

Превращение параметров блока-сценария в моки фреймворк берет на себя.

===== Конец отступления =====



Откуда берется zipper? О нем должен знать наш exporter. Моки заставляют нас делать такие зависимости явными (то есть, использовать Dependency Injection в чистом виде, как я понимаю?). Соответствующим образом дописываем:

OdsExporeterTests >> testGenerates
  [ :zipper |
    exporter zipper: zipper.

    [actualResult := exporter generate] should strictly satisfy: 
          [
          (zipper zip:(Set with: #rootFile with: #contentFile with: #styleFile)) 
              willReturn: #odsFile
          ]
  ] runScenario.
  actualResult should be: #odsFile

Теперь задаем себе вопрос: а откуда взялись #rootFile, #contentFile, #styleFile? Очевидный ответ напрашивается: они должны быть тоже сгенерированы. Кем? Соответствующими компонентами, которые тоже придется добавить (так как у нас нет других подходящих объектов, которым можно было бы приписать соответствующую функциональность). Добавив их, мы столкнемся с вопросом "а из чего они генерят файлы?" Тогда мы поймем, что генерация ODS-файла должна выполняться для определенного контента (worksheet-ов) и с заданным стилем… Ну, вроде, и все — приходим к этом тесту, попутно лишь изменив его название:


OdsExporeterTests >> testGeneratesSubDocuments
  | exporter actualResult |  
  
  exporter := OdsExporter new.

  [ :contentGenerator :styleGenerator :rootGenerator :zipper |

    exporter
      contentGenerator: contentGenertor;
      styleGenerator: styleGenerator;
      rootGenerator: rootGenerator;
      zipper: zipper.

    [actualResult := exporter generate: #worksheets with: #style] 
        should strictly satisfy: 
    [ (contentGenerator generate: #worksheets) 
          willReturn: #contentsFile.
      (styleGenerator generate: #style) 
          willReturn: #styleFile.
      (rootGenerator generateContent: #contentsFile withStyle: #styleFile) 
          willReturn: #rootFile.
      (zipper zip:(Set with: #rootFile with: #contentFile with: #styleFile)) 
          willReturn: #odsFile ]
  
  ] runScenario.
  
  actualResult should be: #odsFile.


Как-то так…


--

Best regards,


Dennis Schetinin


8 декабря 2014 г., 23:04 пользователь Ремизов Александр <[hidden email]> написал:


понедельник, 8 декабря 2014 г., 22:19:21 UTC+4 пользователь chaetal написал:
 Если это не так — готов подробно прокомментировать.

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

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: TDD и вообще юнит-тесты in the wild

Yuriy Mironenko
Проблема с этим примером в том, что "зиппер" уже существует.
И у него есть свой, вполне определенный API.
И лепить какой-нибудь адаптер туда было бы совершенно излишне.



9 декабря 2014 г., 11:52 пользователь Dennis Schetinin <[hidden email]> написал:
Начинаем с чистого листа разработку систему экспорта таблиц в ODS формат. Что мы хотим получить? Некий объект, который умеет "генерить" ODS-файлы:

OdsExporeterTests >> testGenerates
  exporter generate should be: #someOdsFile

Я пока не знаю, что такое ODS-файл, так что использую самую простую заглушку (в виде символа). Но надо понять, откуда берется этот самый ODS-файл? В соответствии с документацией, это результат зипования нескольких файлов, а именно контента, стиля (могут быть еще, но эти два, как я понял, обязательны) и файла с общим описанием — корневого файла. Следовательно в процессе генерации мне понадобится объект, который будет зиповать, и он должен получить соответствующее сообщение с перечнем зипуемых файлов; то, что он вернет в ответ на это сообщение и будет результирующим ODS-файлом:

OdsExporeterTests >> testGenerates
  
  [actualResult := exporter generate] should strictly satisfy: 
        [
        (zipper zip:(Set with: #rootFile with: #contentFile with: #styleFile)) 
            willReturn: #odsFile
        ]

  actualResult should be: #odsFile



===== Отступление =====

Добавленная структура имеет вид:

block1 should strictly satisfy: block2.

Возможность сказать системе, что в процессе выполнения некоторых действий (первый блок) должны быть выполнены следующие действия (второй блок) — как раз и обеспечивает нам Mocketry (или любой другой фреймворк, реализующий mock objects). Собственно, мок — это объект, который создается внутри теста и сначала сохраняет ("записывает") полученные сообщения как "ожидания", а затем — в процессе выполнения теста — проверяет, что ожидания действительно были выполнены:

[systemUnderTest exerciseMessage] should strictly satisfy: [mock someMessage].

Фреймворк сначала включит стадию "записи", в ходе которой выполнит второй блок, отследит получение объектом mock сообщения #someMessage и запомнит это как "ожидание". Затем фреймворк перейдет на стадию "воспроизведения" и выполнит первый блок. Если в процессе ее выполнения mock получить сообщение #someMessage, то ожидание будет помечено как выполненное. Если мок получает неожиданное сообщение, то тест проваливается. Если не все ожидания выполнены, то тест проваливается. 

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

[actualResult := systemUnderTest exerciseMessage] should strictly satisfy: 
    [mock someMessage willReturn: #expectedResult].

Когда объект mock получит сообщение #someMessage, будет возвращено #expectedResult в качестве ответа. И, к примеру, проверка типа

actualResult should be: #expectedResult

будет успешно выполнена.

Mocketry использует концепцию "сценария" чтобы… создать что-то вроде среды для выполнения теста с моками… (Денис Кудряшов, наверное, лучше объяснит этот момент, но она нужна. :)  Эта самая среда создается "внутри" блока, если ему послать сообщение #runScenario. То есть, типичный тест с моками выглядит так:

[ :mock1 :mock2 |
  exerciseBlock should satisfy: expectationsBlock
] runScenario

Превращение параметров блока-сценария в моки фреймворк берет на себя.

===== Конец отступления =====



Откуда берется zipper? О нем должен знать наш exporter. Моки заставляют нас делать такие зависимости явными (то есть, использовать Dependency Injection в чистом виде, как я понимаю?). Соответствующим образом дописываем:

OdsExporeterTests >> testGenerates
  [ :zipper |
    exporter zipper: zipper.

    [actualResult := exporter generate] should strictly satisfy: 
          [
          (zipper zip:(Set with: #rootFile with: #contentFile with: #styleFile)) 
              willReturn: #odsFile
          ]
  ] runScenario.
  actualResult should be: #odsFile

Теперь задаем себе вопрос: а откуда взялись #rootFile, #contentFile, #styleFile? Очевидный ответ напрашивается: они должны быть тоже сгенерированы. Кем? Соответствующими компонентами, которые тоже придется добавить (так как у нас нет других подходящих объектов, которым можно было бы приписать соответствующую функциональность). Добавив их, мы столкнемся с вопросом "а из чего они генерят файлы?" Тогда мы поймем, что генерация ODS-файла должна выполняться для определенного контента (worksheet-ов) и с заданным стилем… Ну, вроде, и все — приходим к этом тесту, попутно лишь изменив его название:


OdsExporeterTests >> testGeneratesSubDocuments
  | exporter actualResult |  
  
  exporter := OdsExporter new.

  [ :contentGenerator :styleGenerator :rootGenerator :zipper |

    exporter
      contentGenerator: contentGenertor;
      styleGenerator: styleGenerator;
      rootGenerator: rootGenerator;
      zipper: zipper.

    [actualResult := exporter generate: #worksheets with: #style] 
        should strictly satisfy: 
    [ (contentGenerator generate: #worksheets) 
          willReturn: #contentsFile.
      (styleGenerator generate: #style) 
          willReturn: #styleFile.
      (rootGenerator generateContent: #contentsFile withStyle: #styleFile) 
          willReturn: #rootFile.
      (zipper zip:(Set with: #rootFile with: #contentFile with: #styleFile)) 
          willReturn: #odsFile ]
  
  ] runScenario.
  
  actualResult should be: #odsFile.


Как-то так…


--

Best regards,


Dennis Schetinin


8 декабря 2014 г., 23:04 пользователь Ремизов Александр <[hidden email]> написал:



понедельник, 8 декабря 2014 г., 22:19:21 UTC+4 пользователь chaetal написал:
 Если это не так — готов подробно прокомментировать.

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

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: TDD и вообще юнит-тесты in the wild

Dennis Schetinin
Разумеется, я в состоянии писать примеры только с позиции своих знаний. Про уже существующий "зиппер" мне не известно. Если расскажите про его API, пример можно будет адаптировать соответствующим образом. 

Единственная трудность, с которой можно столкнуться — вопрос о том, надо ли "мочить" (ударение на первом слоге) уже существующий объект. Этот вопрос в общем случая для меня пока открыт. Каких-то существенных противопоказаний этому я обычно не вижу. 

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

Вместе с тем, есть более-менее устоявшаяся схема размышлений на подобные ситуации: 
  • Если API существующего объекта хорошо ложится в формирующуюся схему взаимодействия разрабатываемой системы (в данном случае — экспортера) с сотрудниками (генераторы контента, стиля, рута и зиппера), то спокойно мОчим с учетом этого API и не паримся
  • Если использование уже существующего объекта ломает схему, то это, скорее всего, означает, что этот API сложноват для наших целей — его нужно адаптировать. Соответственно, не обращаем пока внимание на существование этого объекта и пишем так, как нам удобно. В результате получится обертка/адаптер. 
  • Но бывает, что возиться с этим лениво или некогда — кажется, что "игра не стоит свеч". Тогда можно попробовать классический вариант — описывать не взаимодействие, а результат. Но это, на мой взгляд, самый плохой вариант. На первый взгляд может показаться, что он более короткий и быстрый, но на практике так бывает очень редко. При этом он запутывает систему и делает ее гораздо сложнее. По сути, он является индикатором беспомощности: я просто не знаю как быть. В общем, последнее время я всячески стараюсь его избегать. И наш пример, вроде бы, не выглядит как пример такого поворота событий.

То есть, решение принимается не исходя из каких-то априорных (с точки зрения текущей задачи) предпочтений, а из чисто практических побуждений.


--

Best regards,


Dennis Schetinin


9 декабря 2014 г., 21:30 пользователь Юрий Мироненко <[hidden email]> написал:
Проблема с этим примером в том, что "зиппер" уже существует.
И у него есть свой, вполне определенный API.
И лепить какой-нибудь адаптер туда было бы совершенно излишне.



9 декабря 2014 г., 11:52 пользователь Dennis Schetinin <[hidden email]> написал:

Начинаем с чистого листа разработку систему экспорта таблиц в ODS формат. Что мы хотим получить? Некий объект, который умеет "генерить" ODS-файлы:

OdsExporeterTests >> testGenerates
  exporter generate should be: #someOdsFile

Я пока не знаю, что такое ODS-файл, так что использую самую простую заглушку (в виде символа). Но надо понять, откуда берется этот самый ODS-файл? В соответствии с документацией, это результат зипования нескольких файлов, а именно контента, стиля (могут быть еще, но эти два, как я понял, обязательны) и файла с общим описанием — корневого файла. Следовательно в процессе генерации мне понадобится объект, который будет зиповать, и он должен получить соответствующее сообщение с перечнем зипуемых файлов; то, что он вернет в ответ на это сообщение и будет результирующим ODS-файлом:

OdsExporeterTests >> testGenerates
  
  [actualResult := exporter generate] should strictly satisfy: 
        [
        (zipper zip:(Set with: #rootFile with: #contentFile with: #styleFile)) 
            willReturn: #odsFile
        ]

  actualResult should be: #odsFile



===== Отступление =====

Добавленная структура имеет вид:

block1 should strictly satisfy: block2.

Возможность сказать системе, что в процессе выполнения некоторых действий (первый блок) должны быть выполнены следующие действия (второй блок) — как раз и обеспечивает нам Mocketry (или любой другой фреймворк, реализующий mock objects). Собственно, мок — это объект, который создается внутри теста и сначала сохраняет ("записывает") полученные сообщения как "ожидания", а затем — в процессе выполнения теста — проверяет, что ожидания действительно были выполнены:

[systemUnderTest exerciseMessage] should strictly satisfy: [mock someMessage].

Фреймворк сначала включит стадию "записи", в ходе которой выполнит второй блок, отследит получение объектом mock сообщения #someMessage и запомнит это как "ожидание". Затем фреймворк перейдет на стадию "воспроизведения" и выполнит первый блок. Если в процессе ее выполнения mock получить сообщение #someMessage, то ожидание будет помечено как выполненное. Если мок получает неожиданное сообщение, то тест проваливается. Если не все ожидания выполнены, то тест проваливается. 

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

[actualResult := systemUnderTest exerciseMessage] should strictly satisfy: 
    [mock someMessage willReturn: #expectedResult].

Когда объект mock получит сообщение #someMessage, будет возвращено #expectedResult в качестве ответа. И, к примеру, проверка типа

actualResult should be: #expectedResult

будет успешно выполнена.

Mocketry использует концепцию "сценария" чтобы… создать что-то вроде среды для выполнения теста с моками… (Денис Кудряшов, наверное, лучше объяснит этот момент, но она нужна. :)  Эта самая среда создается "внутри" блока, если ему послать сообщение #runScenario. То есть, типичный тест с моками выглядит так:

[ :mock1 :mock2 |
  exerciseBlock should satisfy: expectationsBlock
] runScenario

Превращение параметров блока-сценария в моки фреймворк берет на себя.

===== Конец отступления =====



Откуда берется zipper? О нем должен знать наш exporter. Моки заставляют нас делать такие зависимости явными (то есть, использовать Dependency Injection в чистом виде, как я понимаю?). Соответствующим образом дописываем:

OdsExporeterTests >> testGenerates
  [ :zipper |
    exporter zipper: zipper.

    [actualResult := exporter generate] should strictly satisfy: 
          [
          (zipper zip:(Set with: #rootFile with: #contentFile with: #styleFile)) 
              willReturn: #odsFile
          ]
  ] runScenario.
  actualResult should be: #odsFile

Теперь задаем себе вопрос: а откуда взялись #rootFile, #contentFile, #styleFile? Очевидный ответ напрашивается: они должны быть тоже сгенерированы. Кем? Соответствующими компонентами, которые тоже придется добавить (так как у нас нет других подходящих объектов, которым можно было бы приписать соответствующую функциональность). Добавив их, мы столкнемся с вопросом "а из чего они генерят файлы?" Тогда мы поймем, что генерация ODS-файла должна выполняться для определенного контента (worksheet-ов) и с заданным стилем… Ну, вроде, и все — приходим к этом тесту, попутно лишь изменив его название:


OdsExporeterTests >> testGeneratesSubDocuments
  | exporter actualResult |  
  
  exporter := OdsExporter new.

  [ :contentGenerator :styleGenerator :rootGenerator :zipper |

    exporter
      contentGenerator: contentGenertor;
      styleGenerator: styleGenerator;
      rootGenerator: rootGenerator;
      zipper: zipper.

    [actualResult := exporter generate: #worksheets with: #style] 
        should strictly satisfy: 
    [ (contentGenerator generate: #worksheets) 
          willReturn: #contentsFile.
      (styleGenerator generate: #style) 
          willReturn: #styleFile.
      (rootGenerator generateContent: #contentsFile withStyle: #styleFile) 
          willReturn: #rootFile.
      (zipper zip:(Set with: #rootFile with: #contentFile with: #styleFile)) 
          willReturn: #odsFile ]
  
  ] runScenario.
  
  actualResult should be: #odsFile.


Как-то так…


--

Best regards,


Dennis Schetinin


8 декабря 2014 г., 23:04 пользователь Ремизов Александр <[hidden email]> написал:



понедельник, 8 декабря 2014 г., 22:19:21 UTC+4 пользователь chaetal написал:
 Если это не так — готов подробно прокомментировать.

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

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: TDD и вообще юнит-тесты in the wild

Сергей Глушенко
In reply to this post by Yuriy Mironenko
 Я слежу  за этой веткой с самого ее создания. В свое время вопрос с TDD и вообще тестированием был очень болезненным. Доходило до шумных скандалов с руководителем (кстати присутствующем здесь) при его попытках ввести тестирование на проекте. На основании опыта работы в том проекте, и работы с текущим собственным проектом в котором я на первых порах то же пытался ввести тестирование я сделал такие выводы:

1. Для того что бы использовать TDD надо обладать очень специфичным складом ума. Думать от обратного надо уметь, все таки большинство людей привыкли к последовательному а не обратному мышлению. TDD как я его понял подразумевает изначальное написание теста охватывающего максимальный функционал разрабатываемого объекта. Вместо объекта подсовывается некий волшебный ящичек  который выполняет требуемую функцию. Затем пишется более детальный тест, дописыватся обвязка ящичка, возможно (а в большинстве случаев именно так и происходит) переписывается вся предыдущая обвязка, и так пока ящичек не перестанет быть нужным. Наверное так можно писать когда четко знаеш что у тебя должно получится в конце.В реальной жизни же так почти никогда не бывает. В начале работы обычно не знаеш что получится на выходе и с чем столкнешся. Есть общее понимание что хотим получить, и в процессе разработки вырисовывается четкая картина реализации. При этом очень часто бывает что она сильно отличается от первоначальной. Тут и подводные камни которые невозможно обойти без изменения изначальной концепции, и какие - то озарения или мысли пришедшие в процессе, да и много еще причин. В случае с TDD это подразумевает переписывание кучи тестов, на и практически всего кода, поскольку как мы помним мы начали с общего случая,и при изменении общей идеи (ну или конечного результата) ломается все уже сделанное. Так что TDD неверное хорош, но в сказке.

2. Автоматические тесты - зло (а вот за это меня побьют). Попробую обосновать.

2.1 100% покрытие тестами невозможно. Так же невозможно помнить (в случае с большим проектом) что покрыто тестами а что не покрыто. Но при разработке помня о том что есть тесты полноценное ручное тестирование не производится. Соответственно не покрытый тестами функционал не тестируется. Отдута и лезет максимальное количество ошибок. С моей точки зрения правильнее четко осознавать свои деиствия и понимать с какими классами и объектами ты работаеш. Не работать сразу с большим количеством классов. Чаше тестировать ручками последствия своих деийствий и стараться понимать к чему они могут привести. Ну и действия с существующим кодом производить только в случае необходимости. Не надо если вам почему- то не понравилось имя класса его менять, то же касается названий методов и переменных. Ну и конечно (но это опять таки мое личное мнение) обязательная проверка входных данных в методах. Например проверка на nil не отнимет много времени, но часто спасает. Даже если по первоначальной задумке там его быть не может.

2.2 Наиболее частые ошибки возникают в UI. Ни и тестирование UI исамое сложное если не невозможное дело. К тому же действия пользователя практически невозможно предсказать. как пример приведу один багрепорт:

LAD, Контроллер любой
Обнаружил случайно. Ставлю блок "Математика". Нажимаю (например) на конец вывод "А" мышкой. Одновременно левую и правую кнопку быстро и несколько раз.
Интерфейс вылетает.

Вот и скажите реально ли такое протестировать.

2.3. Написание тестов неоправданно увеличивают время разработки. Опять таки на личном опыте могу сказать что написание тестов на метод по времени превышает написание самого метода в 3-5 раз в зависимости от сложности метода. Во первых надо создать инстанс объекта, поставить необходимые заглушки и врапперы, а затем надо покрыть все возможные комбинации входных данных. В отдельных случаях на один метод пишется до десятка тестов. В сложном случае при попытке 100% покрытия конечный код просто никогда не будет написан. Ну и естественно при необходимости изменения поведения объекта всю эту кучу тестов необходимо переписывать. В случае развивающегося динамичного проекта использование тестирования ставит на этом проекте крест.

Я предпочитаю использовать разработку через дебаг -с моей точки зрения наиболее быстрый способ разработки. Но вот только он никак не сочетается с тестированием и тем более с TDD.


Ну а теперь можете приступать к избиванию)))))

 

среда, 26 ноября 2014 г., 18:29:43 UTC+5 пользователь Assargadon написал:
Я уже поднимал этот вопрос раньше, но ясность у меня так и не появилась.
Вопрос вот какой: как использовать юнит-тестирование, и тем более TDD - в реальной жизни, а не на абстрактных примерах?

Я умею работать с SUnit, более того - я весьма успешно использовал даже и TDD. Но только в очень специальных случаях. Например, мне нужно было написать калькулятор судебной пошлины с множеством довольно дурацких правил и со странным округлением. Там так и просился TDD - и очень помог. Nile, система для "безопасной арифметики", очень хорошо и удобно покрывается тестами.

Но такой работы, может, 5%-10% от общего вала.
Как применить TDD или хотя бы вообще тесты к остальным 90% ?

Чтобы быть более конкретным - возьмём тот самый Tabular.
Движок для импорта-экспорта таблиц из/в распространённые форматы.
Как его разрабатывать с помощью TDD?

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

Но понятно также, что основная польза, основной полезный код - это именно импортеры-экспортеры.
Как применить TDD к ним?
Я не знаю.

Конечно, под TDD замечательно легла задача "пересчитать номер колонки в её буквенный код". A, B, C, ..., Z, AA, AB, .... и так далее.
Но дальше?

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: TDD и вообще юнит-тесты in the wild

Dennis Schetinin

6 января 2015 г., 19:58 пользователь Сергей Глушенко <[hidden email]> написал:

Для того что бы использовать TDD надо обладать очень специфичным складом ума. Думать от обратного надо уметь <…>  Наверное так можно писать когда четко знаеш что у тебя должно получится в конце.В реальной жизни же так почти никогда не бывает. В начале работы обычно не знаеш что получится на выходе и с чем столкнешся. 

Алиса: – Куда мне отсюда идти?
Ч.Кот: — А куда ты хочешь попасть?
Алиса: — А мне все равно, только бы попасть куда-нибудь.
Ч.Кот: — Тогда все равно куда идти. Куда-нибудь ты обязательно попадешь.

Надо обладать специфичным складом ума, чтобы представлять, куда ты (скажем, впервые) направляешься, не имея возможности представить себе все нюансы маршрута?

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


2. Автоматические тесты - зло <…> 1… 2… 3…

Автомобили зло, потому что:

1. На них можно доехать не до любой точки

2. Чаще всего мы хотим прибыть в какое-либо помещение, а на автомобиле туда заехать невозможно

3. Автомобиль требует массу времени: его надо заправлять, заводить, ремонтировать.

Теперь, внимание, вопрос: а какое все это отношение имеет к автоматизации?

ввести тестирование на проекте

Не устану повторять: TDD и тестирование — принципиально разные вещи. Как автоматизация и автомобиль — даже несмотря на то, что у них общий корень "авто".


--

Best regards,


Dennis Schetinin

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: TDD и вообще юнит-тесты in the wild

Сергей Глушенко
TDD не предполагает какого-либо особого склада ума. Этот подход всего лишь заставляет в каждый момент времени понимать конечную цель своих действий — еще до начала этих самых действий.
 
Возможно в небольших проектах и можно четко представлять себе конечную цель. Заранее продумать всю архитектуру, состав классов и взаимодействие между ними. Но в этом случае проект получится статическим. Его нельзя будет малой кровью модернизировать или где ни будь в середине пути свернуть в сторону. Я год назад начиная свой проект не представлял во что он выльется, имел только смутное представление что я хочу. И теперь я не представляю чем он будет через год. Общая архитектура за это время менялась уже много раз и от базовой архитектуры практически ничего не осталось. Многие связи, и решения как раз возникают в процессе решения задач, а не перед началом работы над задачей. В случае с TTD сначала надо четко себе представить что будет в конце и идти выбранным путем несмотря ни на что. То есть сначала надо очень долго продумывать будущую реализацию. В процессе продумывания можно просто потерять интерес к задаче. Ну или процесс построения будущей архитектуры растянется на непомерно большое время. и не факт что результат будет удачным. Но свернуть то нельзя, потому что изменения тянут за собой глобальные переделки тех же тестов написанных в процессе разработки через TDD.

Ну есть и еще один минус TDD который объеденяет его с тестированием. Глобальное замедление процесса разработки. Посмотрим на реальном примере из моего проекта (полько вчера пробовал).

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

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


isNeededMicrosTimerUtilityFunction



в соответствии с логикой TDD  пишем первый тест (я  свои эксперементы со злости удалил, так что описываю словами)

Создаем Project.
Создаем блок FBDGeneratorBlock.
Добавляем его в проект

 Эта часть подымается родительскому классу что бы в последствии получать блок одним методом

блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет константой.
ставим ему параметр время включенного состояния 1000 милисекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает false


реализация метода что бы тест стал зеленый

isNeededMicrosTimerUtilityFunction

^self onConstantIsMicros.


кстати реализация метода
onConstantIsMicros
то же обвязывается тестами.

Второй тест

Создаем блок
блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет константой.
ставим ему параметр время включенного состояния 1000 микросекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает true


Второй  тест

Создаем блок
блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет константой.
ставим ему параметр время включенного состояния 1000 микросекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает true


Реализация метода не меняется  поскольку метод
onConstantIsMicros
 уже работает правильно

Третий   тест

Создаем блок
блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет вход.
ставим ему параметр время включенного состояния 1000 милисекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает false


Реализация метода не меняется  поскольку метод
onConstantIsMicros
 уже работает правильно

.....

в результате получилось более двадцати тестов на один метод конечный код:

isNeededMicrosTimerUtilityFunction

 
(self isSingle or: [self isSinhroMulty])
 ifTrue
: [^self onConstantIsMicros].
 
^self onConstantIsMicros or: [self offConstantIsMicros]

С той работой с которой я обычно справляюсь за час я провозился день и то до конца не сделал. Ближе к шести вечера (а работаю я с восьми до восьми) я разозлился снес к чертям пакет SUnit вместе со всеми тестами и быстренько все доделал. Я честно пытался понять прелесть TDD но либо я дурак, либо что то в TDD не то. Неприятно считать себя дураком, поэтому я и написал здесь. Может я что то не понимаю, и кто то сможет мне объяснить в чем прелесть использования TDD. По результатам моего небольшого эксперимента он жестко ограничивает свободу разработчика, при этом являясь огромным тормозом в скорости разработки.




вторник, 6 января 2015 г., 23:00:14 UTC+5 пользователь chaetal написал:

6 января 2015 г., 19:58 пользователь Сергей Глушенко <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="z77XkZuxOocJ" onmousedown="this.href='javascript:';return true;" onclick="this.href='javascript:';return true;">sup...@...> написал:

Для того что бы использовать TDD надо обладать очень специфичным складом ума. Думать от обратного надо уметь <…>  Наверное так можно писать когда четко знаеш что у тебя должно получится в конце.В реальной жизни же так почти никогда не бывает. В начале работы обычно не знаеш что получится на выходе и с чем столкнешся. 

Алиса: – Куда мне отсюда идти?
Ч.Кот: — А куда ты хочешь попасть?
Алиса: — А мне все равно, только бы попасть куда-нибудь.
Ч.Кот: — Тогда все равно куда идти. Куда-нибудь ты обязательно попадешь.

Надо обладать специфичным складом ума, чтобы представлять, куда ты (скажем, впервые) направляешься, не имея возможности представить себе все нюансы маршрута?

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


2. Автоматические тесты - зло <…> 1… 2… 3…

Автомобили зло, потому что:

1. На них можно доехать не до любой точки

2. Чаще всего мы хотим прибыть в какое-либо помещение, а на автомобиле туда заехать невозможно

3. Автомобиль требует массу времени: его надо заправлять, заводить, ремонтировать.

Теперь, внимание, вопрос: а какое все это отношение имеет к автоматизации?

ввести тестирование на проекте

Не устану повторять: TDD и тестирование — принципиально разные вещи. Как автоматизация и автомобиль — даже несмотря на то, что у них общий корень "авто".


--

Best regards,


Dennis Schetinin

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: TDD и вообще юнит-тесты in the wild

Yuriy Mironenko
Прежде чем продолжить, Сергей, объясните пару моментов.

Во-первых, почему вы используете логику с побочным эффектом вместо нормальных & и | ? Возможно, здесь скрывается что-то, чего я не понимаю, и потому мои дальнейшие рассуждения тоже будут неверными.

Во-вторых, если я правильно понял, isNeededMicrosTimerUtilityFunction есть логическая функция от четырёх аргументов:
  1. isSingle
  2. isSinhroMulty
  3. onConstantIsMicros
  4. offConstantIsMicros

Поскольку, судя по названиям элементов, там Boolean, всевозможных комбинаций - 16, а вы говорите о 20+ тестах. Откуда берутся дополнительные тесты?

7 января 2015 г., 8:08 пользователь Сергей Глушенко <[hidden email]> написал:
TDD не предполагает какого-либо особого склада ума. Этот подход всего лишь заставляет в каждый момент времени понимать конечную цель своих действий — еще до начала этих самых действий.
 
Возможно в небольших проектах и можно четко представлять себе конечную цель. Заранее продумать всю архитектуру, состав классов и взаимодействие между ними. Но в этом случае проект получится статическим. Его нельзя будет малой кровью модернизировать или где ни будь в середине пути свернуть в сторону. Я год назад начиная свой проект не представлял во что он выльется, имел только смутное представление что я хочу. И теперь я не представляю чем он будет через год. Общая архитектура за это время менялась уже много раз и от базовой архитектуры практически ничего не осталось. Многие связи, и решения как раз возникают в процессе решения задач, а не перед началом работы над задачей. В случае с TTD сначала надо четко себе представить что будет в конце и идти выбранным путем несмотря ни на что. То есть сначала надо очень долго продумывать будущую реализацию. В процессе продумывания можно просто потерять интерес к задаче. Ну или процесс построения будущей архитектуры растянется на непомерно большое время. и не факт что результат будет удачным. Но свернуть то нельзя, потому что изменения тянут за собой глобальные переделки тех же тестов написанных в процессе разработки через TDD.

Ну есть и еще один минус TDD который объеденяет его с тестированием. Глобальное замедление процесса разработки. Посмотрим на реальном примере из моего проекта (полько вчера пробовал).

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

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


isNeededMicrosTimerUtilityFunction



в соответствии с логикой TDD  пишем первый тест (я  свои эксперементы со злости удалил, так что описываю словами)

Создаем Project.
Создаем блок FBDGeneratorBlock.
Добавляем его в проект

 Эта часть подымается родительскому классу что бы в последствии получать блок одним методом

блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет константой.
ставим ему параметр время включенного состояния 1000 милисекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает false


реализация метода что бы тест стал зеленый

isNeededMicrosTimerUtilityFunction

^self onConstantIsMicros.


кстати реализация метода
onConstantIsMicros
то же обвязывается тестами.

Второй тест

Создаем блок
блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет константой.
ставим ему параметр время включенного состояния 1000 микросекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает true


Второй  тест

Создаем блок
блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет константой.
ставим ему параметр время включенного состояния 1000 микросекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает true


Реализация метода не меняется  поскольку метод
onConstantIsMicros
 уже работает правильно

Третий   тест

Создаем блок
блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет вход.
ставим ему параметр время включенного состояния 1000 милисекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает false


Реализация метода не меняется  поскольку метод
onConstantIsMicros
 уже работает правильно

.....

в результате получилось более двадцати тестов на один метод конечный код:

isNeededMicrosTimerUtilityFunction

 
(self isSingle or: [self isSinhroMulty])
 ifTrue
: [^self onConstantIsMicros].
 
^self onConstantIsMicros or: [self offConstantIsMicros]

С той работой с которой я обычно справляюсь за час я провозился день и то до конца не сделал. Ближе к шести вечера (а работаю я с восьми до восьми) я разозлился снес к чертям пакет SUnit вместе со всеми тестами и быстренько все доделал. Я честно пытался понять прелесть TDD но либо я дурак, либо что то в TDD не то. Неприятно считать себя дураком, поэтому я и написал здесь. Может я что то не понимаю, и кто то сможет мне объяснить в чем прелесть использования TDD. По результатам моего небольшого эксперимента он жестко ограничивает свободу разработчика, при этом являясь огромным тормозом в скорости разработки.




вторник, 6 января 2015 г., 23:00:14 UTC+5 пользователь chaetal написал:

6 января 2015 г., 19:58 пользователь Сергей Глушенко <[hidden email]> написал:

Для того что бы использовать TDD надо обладать очень специфичным складом ума. Думать от обратного надо уметь <…>  Наверное так можно писать когда четко знаеш что у тебя должно получится в конце.В реальной жизни же так почти никогда не бывает. В начале работы обычно не знаеш что получится на выходе и с чем столкнешся. 

Алиса: – Куда мне отсюда идти?
Ч.Кот: — А куда ты хочешь попасть?
Алиса: — А мне все равно, только бы попасть куда-нибудь.
Ч.Кот: — Тогда все равно куда идти. Куда-нибудь ты обязательно попадешь.

Надо обладать специфичным складом ума, чтобы представлять, куда ты (скажем, впервые) направляешься, не имея возможности представить себе все нюансы маршрута?

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


2. Автоматические тесты - зло <…> 1… 2… 3…

Автомобили зло, потому что:

1. На них можно доехать не до любой точки

2. Чаще всего мы хотим прибыть в какое-либо помещение, а на автомобиле туда заехать невозможно

3. Автомобиль требует массу времени: его надо заправлять, заводить, ремонтировать.

Теперь, внимание, вопрос: а какое все это отношение имеет к автоматизации?

ввести тестирование на проекте

Не устану повторять: TDD и тестирование — принципиально разные вещи. Как автоматизация и автомобиль — даже несмотря на то, что у них общий корень "авто".


--

Best regards,


Dennis Schetinin

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: TDD и вообще юнит-тесты in the wild

Сергей Глушенко
Просто я не стал разворачивать методы onConstantIsMicros и offConstantIsMicros. Их результат зависит от  типа параметра. Это вход или константа. Соответствено эти варианты необходимо проверять.
И второй вопрос - я не понял а что такое логика с побочными эффектами. Если Вы имеете в в виду что при использовании  self a or:[self b] если а возвращает - true блок or выполняться и метод b просто не вызовется , то это и является основной прелестью такого подхода. Я стараюсь по возможности везде использовать такую конструкцию.  Например если если а возвращает - true то не важно что возвращает метод b,  он вызываться не будет
-- 
С уважением,
Сергей Глушенко
 
 
 
07.01.2015, 11:23, "Юрий Мироненко" <[hidden email]>:
Прежде чем продолжить, Сергей, объясните пару моментов.

Во-первых, почему вы используете логику с побочным эффектом вместо нормальных & и | ? Возможно, здесь скрывается что-то, чего я не понимаю, и потому мои дальнейшие рассуждения тоже будут неверными.
 
Во-вторых, если я правильно понял, isNeededMicrosTimerUtilityFunction есть логическая функция от четырёх аргументов:
  1. isSingle
  2. isSinhroMulty
  3. onConstantIsMicros
  4. offConstantIsMicros
 
Поскольку, судя по названиям элементов, там Boolean, всевозможных комбинаций - 16, а вы говорите о 20+ тестах. Откуда берутся дополнительные тесты?

7 января 2015 г., 8:08 пользователь Сергей Глушенко <[hidden email]> написал:
TDD не предполагает какого-либо особого склада ума. Этот подход всего лишь заставляет в каждый момент времени понимать конечную цель своих действий — еще до начала этих самых действий.
 
Возможно в небольших проектах и можно четко представлять себе конечную цель. Заранее продумать всю архитектуру, состав классов и взаимодействие между ними. Но в этом случае проект получится статическим. Его нельзя будет малой кровью модернизировать или где ни будь в середине пути свернуть в сторону. Я год назад начиная свой проект не представлял во что он выльется, имел только смутное представление что я хочу. И теперь я не представляю чем он будет через год. Общая архитектура за это время менялась уже много раз и от базовой архитектуры практически ничего не осталось. Многие связи, и решения как раз возникают в процессе решения задач, а не перед началом работы над задачей. В случае с TTD сначала надо четко себе представить что будет в конце и идти выбранным путем несмотря ни на что. То есть сначала надо очень долго продумывать будущую реализацию. В процессе продумывания можно просто потерять интерес к задаче. Ну или процесс построения будущей архитектуры растянется на непомерно большое время. и не факт что результат будет удачным. Но свернуть то нельзя, потому что изменения тянут за собой глобальные переделки тех же тестов написанных в процессе разработки через TDD.

Ну есть и еще один минус TDD который объеденяет его с тестированием. Глобальное замедление процесса разработки. Посмотрим на реальном примере из моего проекта (полько вчера пробовал).

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

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


isNeededMicrosTimerUtilityFunction



в соответствии с логикой TDD  пишем первый тест (я  свои эксперементы со злости удалил, так что описываю словами)

Создаем Project.
Создаем блок FBDGeneratorBlock.
Добавляем его в проект

 Эта часть подымается родительскому классу что бы в последствии получать блок одним методом

блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет константой.
ставим ему параметр время включенного состояния 1000 милисекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает false


реализация метода что бы тест стал зеленый

isNeededMicrosTimerUtilityFunction

^self onConstantIsMicros.


кстати реализация метода
onConstantIsMicros
то же обвязывается тестами.

Второй тест

Создаем блок
блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет константой.
ставим ему параметр время включенного состояния 1000 микросекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает true


Второй  тест

Создаем блок
блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет константой.
ставим ему параметр время включенного состояния 1000 микросекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает true


Реализация метода не меняется  поскольку метод
onConstantIsMicros
 уже работает правильно

Третий   тест

Создаем блок
блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет вход.
ставим ему параметр время включенного состояния 1000 милисекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает false


Реализация метода не меняется  поскольку метод
onConstantIsMicros
 уже работает правильно

.....

в результате получилось более двадцати тестов на один метод конечный код:

isNeededMicrosTimerUtilityFunction

 
(self isSingle or: [self isSinhroMulty])
 ifTrue
: [^self onConstantIsMicros].
 
^self onConstantIsMicros or: [self offConstantIsMicros]

С той работой с которой я обычно справляюсь за час я провозился день и то до конца не сделал. Ближе к шести вечера (а работаю я с восьми до восьми) я разозлился снес к чертям пакет SUnit вместе со всеми тестами и быстренько все доделал. Я честно пытался понять прелесть TDD но либо я дурак, либо что то в TDD не то. Неприятно считать себя дураком, поэтому я и написал здесь. Может я что то не понимаю, и кто то сможет мне объяснить в чем прелесть использования TDD. По результатам моего небольшого эксперимента он жестко ограничивает свободу разработчика, при этом являясь огромным тормозом в скорости разработки.




вторник, 6 января 2015 г., 23:00:14 UTC+5 пользователь chaetal написал:

6 января 2015 г., 19:58 пользователь Сергей Глушенко <[hidden email]> написал:
 
 
Для того что бы использовать TDD надо обладать очень специфичным складом ума. Думать от обратного надо уметь <…>  Наверное так можно писать когда четко знаеш что у тебя должно получится в конце.В реальной жизни же так почти никогда не бывает. В начале работы обычно не знаеш что получится на выходе и с чем столкнешся. 
 

Алиса: – Куда мне отсюда идти?
Ч.Кот: — А куда ты хочешь попасть?
Алиса: — А мне все равно, только бы попасть куда-нибудь.
Ч.Кот: — Тогда все равно куда идти. Куда-нибудь ты обязательно попадешь.

Надо обладать специфичным складом ума, чтобы представлять, куда ты (скажем, впервые) направляешься, не имея возможности представить себе все нюансы маршрута?

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

 

2. Автоматические тесты - зло <…> 1… 2… 3…

Автомобили зло, потому что:

1. На них можно доехать не до любой точки

2. Чаще всего мы хотим прибыть в какое-либо помещение, а на автомобиле туда заехать невозможно

3. Автомобиль требует массу времени: его надо заправлять, заводить, ремонтировать.

Теперь, внимание, вопрос: а какое все это отношение имеет к автоматизации?

ввести тестирование на проекте

Не устану повторять: TDD и тестирование — принципиально разные вещи. Как автоматизация и автомобиль — даже несмотря на то, что у них общий корень "авто".

 

--

Best regards,

 

Dennis Schetinin

 

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

 

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на одну из тем в группе "Russian Smalltalk User Group".
Чтобы отменить подписку на эту тему, перейдите по ссылке https://groups.google.com/d/topic/sugr/4ibrvXynivs/unsubscribe.
Чтобы отменить подписку на эту группу и все ее темы, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: TDD и вообще юнит-тесты in the wild

vmusulainen-2
In reply to this post by Сергей Глушенко
CONTENTS DELETED
The author has deleted this message.
Reply | Threaded
Open this post in threaded view
|

Re: TDD и вообще юнит-тесты in the wild

Сергей Глушенко
По поводу Васи тут двоякая ситуация.  В той же ситуации с релизом и багой. Петя а почему ты не написал тест?. Как возможно не проверить ситуацию при ручной проверке, то точ но так же и возможно просто не написать тест на эту ситуацию. Только без тестов Вася с Петей занимаются выпуском версий выполняя полезную работу, а в случае качественного тестирования и поддержания тестов в рабочем состоянии занимаются только этим. И релиза от них не дождешся. Если на каждый чих надо переписать тонну кода то и чих то делать расхочется. Да и не согласен я с тем что написание тестов помогает Пете с пониманием проекта написанного Васей. Как бы не усложняет. Для тестов в классах приходится делать дополнительные вспомогательные методы, что то закрывается моками и врапперами. Да и общее количество кода необходимого для просмотра и понимания возрастает в разы. В базовом образе SmallTalk нет тестов, но между тем мы довольно таки легко находим нужные нам классы и методы. Я то же не помню что я делал год назад, так что при доработке старых классов могу сравнить себя с тем Петей. Вопрос в написании адекватных названий классов методов. Возможно не всегда правильных с точки зрения орфографии, но понятных с первого взгляда. Ну и при необходимости в особо сложных случаев написание комментов. Думаю это более простое и доступное решение чем документирование с помощью тестов.

я думаю из названий этих классов любому знакомому с предметной областью программистом будет все понятно
AbstractBlock
   
AbstractLADElement
       
LADManyInputsBlock
           
LADBlocksWithoutVariables
               
LADAnalogSwith
               
LADRealTimeClockSetTimeBlock
               
LADScaleBlock
               
LADBounceBlock
               
LADCounterBlock
               
LADStepMotorBlock
               
LADCommPortBlock
               
LADDisplayOnChipHD44780Block
               
LADRealTimeClockAlarmBlock
               
LADRealTimeClockGetTime
               
LADArithmeticBlock
               
LADServoMotorBlock
               
LADStandartFunctionBlock
                   
LADABSBlock
                   
LADCosBlock
                   
LADMAXBlock
                   
LADMINBlock
                   
LADPOWBlock
                   
LADRANDOMBlock
                   
LADSinBlock
                   
LADSQBlock
                   
LADSQRTBlock
                   
LADTanBlock
               
LADUltrasonicBlock
               
LADIrRessiveBlock
               
LADDisplayOnChipHD4480I2CBacklightControlBlock
               
LADAbstractSDBlocks
                   
LADSaveToSDVariableBlock
                   
LADUploadFileFromSDBlock
               
LADConvertFloatToIntegerBlock
               
LADBlocksWithTypeAndUpdateTime
                    LADBMP085Block
                   
LADDigitalTemperatureAndHumidityBlock
                    LADDS18x2xBlock
               
LADChip74HC595Block
               
LADSevenSegmentDecoderBlock
               
LADManyInputsSwithBlock
               
LADManyOutputsSwithBlock
               
LADBitCoderBlock
               
LADBitDecodeBlock
               
LADBitReadeBlock
               
LADBitWriteBlock
               
LADMatrixKeyboardBlock
               
LADPiezoSpeakerBlock
               
LADReadFromEepromBlock
               
LADSaveToEepromBlock
               
LADSendRessiveVariableFromCommunication
                   
LADRessiveVariableFromCommunication
                   
LADSendVariableFromCommunication
               
LADWebServises
                   
LADWebServerPage
                   
LADWebClient
           
LADSummStringBlock
           
LADSpecialCoil
               
LADCompareCoil
               
LADTriggerCoil
               
LADTimerCoil
               
LADGenCoil
           
LADConvertStringBlock
       
LADBasicElement
           
LADContact
           
LADCoil
               
LadRtrigCoil
       
LADAnalogInputOutputBlock
           
LADAnalogConductorInput
           
LADAnalogInput
           
LADAnalogConductoOutput
           
LADAnalogOutput
       
LADSendRessiveVariablesBlocks
           
LADRessiveVariablesBlocks
           
LADSendVariableBlock
       
LADSpeedCounterBlock
   
AbstractElement
       
BlocksWithType
           
BlocksWithTypeAndCollectionOutputs
               
BlocksWithTypeAndCollectionInputsOutputs
                   
FBDSwitchBlock
                   
FBDArithmeticBlock
                   
FBDBounceBlock
                   
FBDSummStringBlock
                   
FBDTimerBlock
                   
FBDServoMotorBlock
                   
FBDBasicLogikBlock
                   
FBDCommPortBlock
                   
FBDCompareBlock
                   
FBDTriggerBlock
                   
ALADAnalogConductoOutput
                   
FBDStandartFunctionBlock
                   
FBDConvertStringBlock
               
FBDGeneratorBlock
           
CounterBlock
           
FBDStepMotorBlock
           
FBDDisplayOnChipHD44780Block
           
FBDRealTimeClockAlarmBlock
           
FBDRealTimeClockSetTimeBlock
           
FBDRealTimeClockGetTimeBlock
           
FBDScaleBlock
           
FBDUltrasonicBlock
           
FBDIrRessiveBlock
           
FBDDisplayOnChipHD4480I2CBacklightControlBlock
           
FBDAbstractSDBlocks
               
FBDSaveToSDVariableBlock
               
FBDUploadFileFromSDBlock
           
FBDConvertFloatToIntegerBlock
           
FBDBlocksWithTypeAndUpdateTime
               
FBDDigitalTemperatureAndHumidityBlock
                FBDDS18x2xBlock
                FBDBMP085Block
           
FBDChip74HC595Block
           
FBDSevenSegmentDecoderBlock
           
FBDManyInputsSwithBlock
           
FBDManyOutputsSwithBlock
           
FBDBitCoderBlock
           
FBDBitDecodeBlock
           
FBDBitReadBlock
           
FBDBitWriteBlock
           
FBDMatrixKeyboardBlock
           
FBDPiezoSpeakerBlock
           
FBDSaveToEepromBlock
           
FBDReadFromEepromBlock
           
FBDWebServises
               
FBDWebServerPage
               
FBDWebClient
               
FBDNarodMonRuClient
       
TagBlock
       
SendRessiveVariablesBlocks
           
SendVariableBlock
           
RessiveVariablesBlocks
       
SpeedCounterBlock
       
FBDSendRessiveVariableFromCommunication
           
FBDRessiveVariableFromCommunication
           
FBDSendVariableFromCommunication




среда, 7 января 2015 г., 12:30:02 UTC+5 пользователь Vladimir Musulainen написал:


среда, 7 января 2015 г., 8:08:03 UTC+3 пользователь Сергей Глушенко написал:

isNeededMicrosTimerUtilityFunction

 
(self isSingle or: [self isSinhroMulty])
 ifTrue
: [^self onConstantIsMicros].
 
^self onConstantIsMicros or: [self offConstantIsMicros]



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

Отмечу несколько моментов относительно TDD и тестирования:
1. Если разработчик проекта один и он все держит под контролем, то нужды в автоматическом тестировании нет. Как и во многих других практиках программирования как-то: code style, version control system и тому подобное. Единственный разработчик может обзывать классы/методы хоть на китайском. Не пользоваться CVS/GIT/по вкусу и версии держать в виде папок с архивами. Не иметь тестов вообще. И это никак особо не повлияет на скорость его работы. Но вот, как только туда придет второй программист, вот тут начнется попа. Ибо они будут разговаривать на разных языках, обмениваться папками с исходниками для передачи изменений в коде и нервничать на тем: 'Я внес изменение в программу в метод, который часто используется - как мне проверить, что ничего не сломалось? Ответ - руками запустить программу и вызывать много сценариев работы. Уп-с, выпустили релиз с багой. Петя, а почему ты не проверил такой сценарий? Вася, а что и такой мог быть?' И тут начнется создание чек-листов с сценариями для ручной проверки и тому подобное. 
2. Не надо тестировать, то что тестируется плохо. Плохо тестируется UI - не тестируйте. Не надо писать  тестов на каждый метод, включая ассессоры. Это я говорю касательно unit-тестирования. Рассматривайте класс, как черный ящик. Вы дергаете за рычаги на нем и он должен вам выдать золотой слиток. Это и описывает тест. 

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: TDD и вообще юнит-тесты in the wild

Yuriy Mironenko
In reply to this post by Yuriy Mironenko
Теперь, Денис, вопрос и тебе.

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

Очевидное решение здесь - написать таблицу истинности и по ней всё проверить. В одном тесте, не в двадцати :)

Но тут возникает очевидный вопрос: уж если есть таблица истинности, то проще считать её реализацией метода, а не его проверкой.

7 января 2015 г., 9:23 пользователь Юрий Мироненко <[hidden email]> написал:
Прежде чем продолжить, Сергей, объясните пару моментов.

Во-первых, почему вы используете логику с побочным эффектом вместо нормальных & и | ? Возможно, здесь скрывается что-то, чего я не понимаю, и потому мои дальнейшие рассуждения тоже будут неверными.

Во-вторых, если я правильно понял, isNeededMicrosTimerUtilityFunction есть логическая функция от четырёх аргументов:
  1. isSingle
  2. isSinhroMulty
  3. onConstantIsMicros
  4. offConstantIsMicros

Поскольку, судя по названиям элементов, там Boolean, всевозможных комбинаций - 16, а вы говорите о 20+ тестах. Откуда берутся дополнительные тесты?

7 января 2015 г., 8:08 пользователь Сергей Глушенко <[hidden email]> написал:

TDD не предполагает какого-либо особого склада ума. Этот подход всего лишь заставляет в каждый момент времени понимать конечную цель своих действий — еще до начала этих самых действий.
 
Возможно в небольших проектах и можно четко представлять себе конечную цель. Заранее продумать всю архитектуру, состав классов и взаимодействие между ними. Но в этом случае проект получится статическим. Его нельзя будет малой кровью модернизировать или где ни будь в середине пути свернуть в сторону. Я год назад начиная свой проект не представлял во что он выльется, имел только смутное представление что я хочу. И теперь я не представляю чем он будет через год. Общая архитектура за это время менялась уже много раз и от базовой архитектуры практически ничего не осталось. Многие связи, и решения как раз возникают в процессе решения задач, а не перед началом работы над задачей. В случае с TTD сначала надо четко себе представить что будет в конце и идти выбранным путем несмотря ни на что. То есть сначала надо очень долго продумывать будущую реализацию. В процессе продумывания можно просто потерять интерес к задаче. Ну или процесс построения будущей архитектуры растянется на непомерно большое время. и не факт что результат будет удачным. Но свернуть то нельзя, потому что изменения тянут за собой глобальные переделки тех же тестов написанных в процессе разработки через TDD.

Ну есть и еще один минус TDD который объеденяет его с тестированием. Глобальное замедление процесса разработки. Посмотрим на реальном примере из моего проекта (полько вчера пробовал).

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

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


isNeededMicrosTimerUtilityFunction



в соответствии с логикой TDD  пишем первый тест (я  свои эксперементы со злости удалил, так что описываю словами)

Создаем Project.
Создаем блок FBDGeneratorBlock.
Добавляем его в проект

 Эта часть подымается родительскому классу что бы в последствии получать блок одним методом

блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет константой.
ставим ему параметр время включенного состояния 1000 милисекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает false


реализация метода что бы тест стал зеленый

isNeededMicrosTimerUtilityFunction

^self onConstantIsMicros.


кстати реализация метода
onConstantIsMicros
то же обвязывается тестами.

Второй тест

Создаем блок
блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет константой.
ставим ему параметр время включенного состояния 1000 микросекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает true


Второй  тест

Создаем блок
блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет константой.
ставим ему параметр время включенного состояния 1000 микросекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает true


Реализация метода не меняется  поскольку метод
onConstantIsMicros
 уже работает правильно

Третий   тест

Создаем блок
блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет вход.
ставим ему параметр время включенного состояния 1000 милисекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает false


Реализация метода не меняется  поскольку метод
onConstantIsMicros
 уже работает правильно

.....

в результате получилось более двадцати тестов на один метод конечный код:

isNeededMicrosTimerUtilityFunction

 
(self isSingle or: [self isSinhroMulty])
 ifTrue
: [^self onConstantIsMicros].
 
^self onConstantIsMicros or: [self offConstantIsMicros]

С той работой с которой я обычно справляюсь за час я провозился день и то до конца не сделал. Ближе к шести вечера (а работаю я с восьми до восьми) я разозлился снес к чертям пакет SUnit вместе со всеми тестами и быстренько все доделал. Я честно пытался понять прелесть TDD но либо я дурак, либо что то в TDD не то. Неприятно считать себя дураком, поэтому я и написал здесь. Может я что то не понимаю, и кто то сможет мне объяснить в чем прелесть использования TDD. По результатам моего небольшого эксперимента он жестко ограничивает свободу разработчика, при этом являясь огромным тормозом в скорости разработки.




вторник, 6 января 2015 г., 23:00:14 UTC+5 пользователь chaetal написал:

6 января 2015 г., 19:58 пользователь Сергей Глушенко <[hidden email]> написал:

Для того что бы использовать TDD надо обладать очень специфичным складом ума. Думать от обратного надо уметь <…>  Наверное так можно писать когда четко знаеш что у тебя должно получится в конце.В реальной жизни же так почти никогда не бывает. В начале работы обычно не знаеш что получится на выходе и с чем столкнешся. 

Алиса: – Куда мне отсюда идти?
Ч.Кот: — А куда ты хочешь попасть?
Алиса: — А мне все равно, только бы попасть куда-нибудь.
Ч.Кот: — Тогда все равно куда идти. Куда-нибудь ты обязательно попадешь.

Надо обладать специфичным складом ума, чтобы представлять, куда ты (скажем, впервые) направляешься, не имея возможности представить себе все нюансы маршрута?

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


2. Автоматические тесты - зло <…> 1… 2… 3…

Автомобили зло, потому что:

1. На них можно доехать не до любой точки

2. Чаще всего мы хотим прибыть в какое-либо помещение, а на автомобиле туда заехать невозможно

3. Автомобиль требует массу времени: его надо заправлять, заводить, ремонтировать.

Теперь, внимание, вопрос: а какое все это отношение имеет к автоматизации?

ввести тестирование на проекте

Не устану повторять: TDD и тестирование — принципиально разные вещи. Как автоматизация и автомобиль — даже несмотря на то, что у них общий корень "авто".


--

Best regards,


Dennis Schetinin

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.


--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: TDD и вообще юнит-тесты in the wild

Сергей Глушенко
Изначально у меня то же в этом методе было что то вроде таблицы истинности (пришол как раз через эксперимент с TDD) но затем знание о виде конкретного параметра мне понадобилось в компиляторе и было вынесенно в метод. Да и вообще реализация конкретного метода мне кажется расскажет о его работе быстрее и понятнее чем куча тестовых методов вокруг него. С моей точки зрения главное стараться делать методы максимально короткими. Сложные конструкции надо сразу же выносить в отдельные методы, тогда и работа конкретного метода будет сразу понятна с первого взгляда и никакие тесты не нужны будут

среда, 7 января 2015 г., 13:55:19 UTC+5 пользователь Assargadon написал:
Теперь, Денис, вопрос и тебе.

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

Очевидное решение здесь - написать таблицу истинности и по ней всё проверить. В одном тесте, не в двадцати :)

Но тут возникает очевидный вопрос: уж если есть таблица истинности, то проще считать её реализацией метода, а не его проверкой.

7 января 2015 г., 9:23 пользователь Юрий Мироненко <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="cNfIqyyq-ioJ" onmousedown="this.href='javascript:';return true;" onclick="this.href='javascript:';return true;">assar...@...> написал:
Прежде чем продолжить, Сергей, объясните пару моментов.

Во-первых, почему вы используете логику с побочным эффектом вместо нормальных & и | ? Возможно, здесь скрывается что-то, чего я не понимаю, и потому мои дальнейшие рассуждения тоже будут неверными.

Во-вторых, если я правильно понял, isNeededMicrosTimerUtilityFunction есть логическая функция от четырёх аргументов:
  1. isSingle
  2. isSinhroMulty
  3. onConstantIsMicros
  4. offConstantIsMicros

Поскольку, судя по названиям элементов, там Boolean, всевозможных комбинаций - 16, а вы говорите о 20+ тестах. Откуда берутся дополнительные тесты?

7 января 2015 г., 8:08 пользователь Сергей Глушенко <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="cNfIqyyq-ioJ" onmousedown="this.href='javascript:';return true;" onclick="this.href='javascript:';return true;">sup...@...> написал:

TDD не предполагает какого-либо особого склада ума. Этот подход всего лишь заставляет в каждый момент времени понимать конечную цель своих действий — еще до начала этих самых действий.
 
Возможно в небольших проектах и можно четко представлять себе конечную цель. Заранее продумать всю архитектуру, состав классов и взаимодействие между ними. Но в этом случае проект получится статическим. Его нельзя будет малой кровью модернизировать или где ни будь в середине пути свернуть в сторону. Я год назад начиная свой проект не представлял во что он выльется, имел только смутное представление что я хочу. И теперь я не представляю чем он будет через год. Общая архитектура за это время менялась уже много раз и от базовой архитектуры практически ничего не осталось. Многие связи, и решения как раз возникают в процессе решения задач, а не перед началом работы над задачей. В случае с TTD сначала надо четко себе представить что будет в конце и идти выбранным путем несмотря ни на что. То есть сначала надо очень долго продумывать будущую реализацию. В процессе продумывания можно просто потерять интерес к задаче. Ну или процесс построения будущей архитектуры растянется на непомерно большое время. и не факт что результат будет удачным. Но свернуть то нельзя, потому что изменения тянут за собой глобальные переделки тех же тестов написанных в процессе разработки через TDD.

Ну есть и еще один минус TDD который объеденяет его с тестированием. Глобальное замедление процесса разработки. Посмотрим на реальном примере из моего проекта (полько вчера пробовал).

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

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


isNeededMicrosTimerUtilityFunction



в соответствии с логикой TDD  пишем первый тест (я  свои эксперементы со злости удалил, так что описываю словами)

Создаем Project.
Создаем блок FBDGeneratorBlock.
Добавляем его в проект

 Эта часть подымается родительскому классу что бы в последствии получать блок одним методом

блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет константой.
ставим ему параметр время включенного состояния 1000 милисекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает false


реализация метода что бы тест стал зеленый

isNeededMicrosTimerUtilityFunction

^self onConstantIsMicros.


кстати реализация метода
onConstantIsMicros
то же обвязывается тестами.

Второй тест

Создаем блок
блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет константой.
ставим ему параметр время включенного состояния 1000 микросекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает true


Второй  тест

Создаем блок
блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет константой.
ставим ему параметр время включенного состояния 1000 микросекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает true


Реализация метода не меняется  поскольку метод
onConstantIsMicros
 уже работает правильно

Третий   тест

Создаем блок
блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет вход.
ставим ему параметр время включенного состояния 1000 милисекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает false


Реализация метода не меняется  поскольку метод
onConstantIsMicros
 уже работает правильно

.....

в результате получилось более двадцати тестов на один метод конечный код:

isNeededMicrosTimerUtilityFunction

 
(self isSingle or: [self isSinhroMulty])
 ifTrue
: [^self onConstantIsMicros].
 
^self onConstantIsMicros or: [self offConstantIsMicros]

С той работой с которой я обычно справляюсь за час я провозился день и то до конца не сделал. Ближе к шести вечера (а работаю я с восьми до восьми) я разозлился снес к чертям пакет SUnit вместе со всеми тестами и быстренько все доделал. Я честно пытался понять прелесть TDD но либо я дурак, либо что то в TDD не то. Неприятно считать себя дураком, поэтому я и написал здесь. Может я что то не понимаю, и кто то сможет мне объяснить в чем прелесть использования TDD. По результатам моего небольшого эксперимента он жестко ограничивает свободу разработчика, при этом являясь огромным тормозом в скорости разработки.




вторник, 6 января 2015 г., 23:00:14 UTC+5 пользователь chaetal написал:

6 января 2015 г., 19:58 пользователь Сергей Глушенко <[hidden email]> написал:

Для того что бы использовать TDD надо обладать очень специфичным складом ума. Думать от обратного надо уметь <…>  Наверное так можно писать когда четко знаеш что у тебя должно получится в конце.В реальной жизни же так почти никогда не бывает. В начале работы обычно не знаеш что получится на выходе и с чем столкнешся. 

Алиса: – Куда мне отсюда идти?
Ч.Кот: — А куда ты хочешь попасть?
Алиса: — А мне все равно, только бы попасть куда-нибудь.
Ч.Кот: — Тогда все равно куда идти. Куда-нибудь ты обязательно попадешь.

Надо обладать специфичным складом ума, чтобы представлять, куда ты (скажем, впервые) направляешься, не имея возможности представить себе все нюансы маршрута?

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


2. Автоматические тесты - зло <…> 1… 2… 3…

Автомобили зло, потому что:

1. На них можно доехать не до любой точки

2. Чаще всего мы хотим прибыть в какое-либо помещение, а на автомобиле туда заехать невозможно

3. Автомобиль требует массу времени: его надо заправлять, заводить, ремонтировать.

Теперь, внимание, вопрос: а какое все это отношение имеет к автоматизации?

ввести тестирование на проекте

Не устану повторять: TDD и тестирование — принципиально разные вещи. Как автоматизация и автомобиль — даже несмотря на то, что у них общий корень "авто".


--

Best regards,


Dennis Schetinin

--
--
<a href="http://groups.google.ru/group/sugr" target="_blank" onmousedown="this.href='http://groups.google.ru/group/sugr';return true;" onclick="this.href='http://groups.google.ru/group/sugr';return true;">http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес <a href="javascript:" target="_blank" gdf-obfuscated-mailto="cNfIqyyq-ioJ" onmousedown="this.href='javascript:';return true;" onclick="this.href='javascript:';return true;">sugr+uns...@googlegroups.com.
Чтобы настроить другие параметры, перейдите по ссылке <a href="https://groups.google.com/d/optout" target="_blank" onmousedown="this.href='https://groups.google.com/d/optout';return true;" onclick="this.href='https://groups.google.com/d/optout';return true;">https://groups.google.com/d/optout.


--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: TDD и вообще юнит-тесты in the wild

Nikolay Kleptsov
Добавлю небольшую ремарку.
Тесты не влияют на производительность приложения, они находятся как-бы в стороне.
При создании классов так или иначе приходится испытывать класс (Workspace, Debuger) TDD будет приятным дополнением.
Добавление тестов занимает меньше 5% разработки.
Понимание кода улучшается, анализируя методы тестов.
Отладчик показывает стек сообщений, большую часть ошибок можно исправить, а если ошибка не связана напрямую.
ТDD тоже не панацея от всего и все-таки

7 января 2015 г., 15:12 пользователь Сергей Глушенко <[hidden email]> написал:
Изначально у меня то же в этом методе было что то вроде таблицы истинности (пришол как раз через эксперимент с TDD) но затем знание о виде конкретного параметра мне понадобилось в компиляторе и было вынесенно в метод. Да и вообще реализация конкретного метода мне кажется расскажет о его работе быстрее и понятнее чем куча тестовых методов вокруг него. С моей точки зрения главное стараться делать методы максимально короткими. Сложные конструкции надо сразу же выносить в отдельные методы, тогда и работа конкретного метода будет сразу понятна с первого взгляда и никакие тесты не нужны будут

среда, 7 января 2015 г., 13:55:19 UTC+5 пользователь Assargadon написал:
Теперь, Денис, вопрос и тебе.

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

Очевидное решение здесь - написать таблицу истинности и по ней всё проверить. В одном тесте, не в двадцати :)

Но тут возникает очевидный вопрос: уж если есть таблица истинности, то проще считать её реализацией метода, а не его проверкой.

7 января 2015 г., 9:23 пользователь Юрий Мироненко <[hidden email]> написал:
Прежде чем продолжить, Сергей, объясните пару моментов.

Во-первых, почему вы используете логику с побочным эффектом вместо нормальных & и | ? Возможно, здесь скрывается что-то, чего я не понимаю, и потому мои дальнейшие рассуждения тоже будут неверными.

Во-вторых, если я правильно понял, isNeededMicrosTimerUtilityFunction есть логическая функция от четырёх аргументов:
  1. isSingle
  2. isSinhroMulty
  3. onConstantIsMicros
  4. offConstantIsMicros

Поскольку, судя по названиям элементов, там Boolean, всевозможных комбинаций - 16, а вы говорите о 20+ тестах. Откуда берутся дополнительные тесты?

7 января 2015 г., 8:08 пользователь Сергей Глушенко <[hidden email]> написал:

TDD не предполагает какого-либо особого склада ума. Этот подход всего лишь заставляет в каждый момент времени понимать конечную цель своих действий — еще до начала этих самых действий.
 
Возможно в небольших проектах и можно четко представлять себе конечную цель. Заранее продумать всю архитектуру, состав классов и взаимодействие между ними. Но в этом случае проект получится статическим. Его нельзя будет малой кровью модернизировать или где ни будь в середине пути свернуть в сторону. Я год назад начиная свой проект не представлял во что он выльется, имел только смутное представление что я хочу. И теперь я не представляю чем он будет через год. Общая архитектура за это время менялась уже много раз и от базовой архитектуры практически ничего не осталось. Многие связи, и решения как раз возникают в процессе решения задач, а не перед началом работы над задачей. В случае с TTD сначала надо четко себе представить что будет в конце и идти выбранным путем несмотря ни на что. То есть сначала надо очень долго продумывать будущую реализацию. В процессе продумывания можно просто потерять интерес к задаче. Ну или процесс построения будущей архитектуры растянется на непомерно большое время. и не факт что результат будет удачным. Но свернуть то нельзя, потому что изменения тянут за собой глобальные переделки тех же тестов написанных в процессе разработки через TDD.

Ну есть и еще один минус TDD который объеденяет его с тестированием. Глобальное замедление процесса разработки. Посмотрим на реальном примере из моего проекта (полько вчера пробовал).

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

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


isNeededMicrosTimerUtilityFunction



в соответствии с логикой TDD  пишем первый тест (я  свои эксперементы со злости удалил, так что описываю словами)

Создаем Project.
Создаем блок FBDGeneratorBlock.
Добавляем его в проект

 Эта часть подымается родительскому классу что бы в последствии получать блок одним методом

блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет константой.
ставим ему параметр время включенного состояния 1000 милисекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает false


реализация метода что бы тест стал зеленый

isNeededMicrosTimerUtilityFunction

^self onConstantIsMicros.


кстати реализация метода
onConstantIsMicros
то же обвязывается тестами.

Второй тест

Создаем блок
блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет константой.
ставим ему параметр время включенного состояния 1000 микросекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает true


Второй  тест

Создаем блок
блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет константой.
ставим ему параметр время включенного состояния 1000 микросекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает true


Реализация метода не меняется  поскольку метод
onConstantIsMicros
 уже работает правильно

Третий   тест

Создаем блок
блоку говорим что он одновибратор
говорим ему что параметр  время включенного состояния будет вход.
ставим ему параметр время включенного состояния 1000 милисекунд.
проверяем что метод isNeededMicrosTimerUtilityFunction возвращает false


Реализация метода не меняется  поскольку метод
onConstantIsMicros
 уже работает правильно

.....

в результате получилось более двадцати тестов на один метод конечный код:

isNeededMicrosTimerUtilityFunction

 
(self isSingle or: [self isSinhroMulty])
 ifTrue
: [^self onConstantIsMicros].
 
^self onConstantIsMicros or: [self offConstantIsMicros]

С той работой с которой я обычно справляюсь за час я провозился день и то до конца не сделал. Ближе к шести вечера (а работаю я с восьми до восьми) я разозлился снес к чертям пакет SUnit вместе со всеми тестами и быстренько все доделал. Я честно пытался понять прелесть TDD но либо я дурак, либо что то в TDD не то. Неприятно считать себя дураком, поэтому я и написал здесь. Может я что то не понимаю, и кто то сможет мне объяснить в чем прелесть использования TDD. По результатам моего небольшого эксперимента он жестко ограничивает свободу разработчика, при этом являясь огромным тормозом в скорости разработки.




вторник, 6 января 2015 г., 23:00:14 UTC+5 пользователь chaetal написал:

6 января 2015 г., 19:58 пользователь Сергей Глушенко <[hidden email]> написал:

Для того что бы использовать TDD надо обладать очень специфичным складом ума. Думать от обратного надо уметь <…>  Наверное так можно писать когда четко знаеш что у тебя должно получится в конце.В реальной жизни же так почти никогда не бывает. В начале работы обычно не знаеш что получится на выходе и с чем столкнешся. 

Алиса: – Куда мне отсюда идти?
Ч.Кот: — А куда ты хочешь попасть?
Алиса: — А мне все равно, только бы попасть куда-нибудь.
Ч.Кот: — Тогда все равно куда идти. Куда-нибудь ты обязательно попадешь.

Надо обладать специфичным складом ума, чтобы представлять, куда ты (скажем, впервые) направляешься, не имея возможности представить себе все нюансы маршрута?

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


2. Автоматические тесты - зло <…> 1… 2… 3…

Автомобили зло, потому что:

1. На них можно доехать не до любой точки

2. Чаще всего мы хотим прибыть в какое-либо помещение, а на автомобиле туда заехать невозможно

3. Автомобиль требует массу времени: его надо заправлять, заводить, ремонтировать.

Теперь, внимание, вопрос: а какое все это отношение имеет к автоматизации?

ввести тестирование на проекте

Не устану повторять: TDD и тестирование — принципиально разные вещи. Как автоматизация и автомобиль — даже несмотря на то, что у них общий корень "авто".


--

Best regards,


Dennis Schetinin

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес sugr+uns...@googlegroups.com.
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.


--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

--
--
http://groups.google.ru/group/sugr
---
Вы получили это сообщение, поскольку подписаны на группу "Russian Smalltalk User Group".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес [hidden email].
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.
1234