Как научиться писать юнит-тесты, в которых будет смысл и не ошалеть от скуки?
===============================================================================

 Хочу признаться: за всю жизнь я написал меньше 10 юнит-тестов. Это при том, что люблю и часто пишу библиотечные проекты. Каждый раз перед началом проекта я говорю себе: в этот раз я буду писать юнит-тесты. Естественно, нарушаю обещание.  
  
  

В оправдание могу сказать, что просто не понимаю, как подступиться к этой задаче. Допустим, я написал некий контейнер на Яве. Но чтобы хотя бы наполовину покрыть качественно различные состояния контейнера тестами, надо написать в несколько раз больше кода, чем занимает сам контейнер! А если он содержит слабые ссылки? А если он потокобезопасный? Сами тесты в этих случаях становится непросто написать. Особенно так, чтобы они были корректными.  
  
  

Я вижу, что чем сложнее интерфейс, тем многократно сложнее его протестировать.  
  
  

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

Кстати, вопрос не Ява-специфичный. 

 Знакомая проблема. Хорошо писать тесты для простой функциональности. Но что делать, когда нужно тестировать не просто отдельные функции, а ещё и их комбинации? Что делать, когда количество комбинаций входных данных — огромно, или вообще бесконечно, и каждая комбинация может привести к ошибке?  

  

Для себя нашёл частичный выход: пишу высокоуровневые тесты, а низкоуровневые заменяю множеством assert-ов. Assert проще написать, поскольку не надо воспроизводить контекст ни программно, ни мысленно — assert всегда выполняется в нужном контексте. И при запуске высокоуровнего теста фактически выполняется гораздо больше проверок, чем написано в самом тесте. Assert-ты также очень помогают в отладке — с их помощью быстрее локализуются ошибки.  

  

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

 Полагаю, для этого и нанимают отдельных людей, которые пишут исключительно тесты. 

 Ну во первых написание в несколько раз большего кода не является проблемой. Ибо есть правило: «написание кода не является узким местом разработки». Узкое место это например постоянный реинжениринг дизайна. Тестов и должно быть больше, чем оснвоного кода, но код тестов должен быть простым, и легко пишушимся. Что-то подали на вход, что-то получили на выходе.  

  

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

  

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

 Так как вопрос в общем, то в общем уменьшение использования состояний уменьшает сложность тестирования. Например, при использовании функцонального стиля. 

       Попробуй почитать об TDD - Test-driven development. Это техника разработки через тестирование, которая позволить сделать процесс написания юнит-тестов частью написания кода, точнее ты будешь писать код который бы удовлетворял написанному тесту. Такая техника сделает процесс написания юнит-тестов намного интересней и эффективней, а время затрачиваемое на кодирование в целом уменьшиться, потому что уменьшиться время обычно затрачиваемое на отладку и поиск ошибок.