powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / Помогите танкисту с TDD
11 сообщений из 11, страница 1 из 1
Помогите танкисту с TDD
    #38853647
DDiver
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
У меня два фундаментальных вопроса, поэтому вопрос как бы из двух частей.

Допустим у нас есть интерфейс, для примера возьмём один метод
Код: java
1.
2.
3.
4.
5.
public interface TableBuilder {
...
    void addRowItem(String itemValue);
...
}


как пишут очень вумные дядьки в книжках, для написания кода этого метода нужны приблизительно следующие методы в тесте
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
public class TableBuilderTest {
...
    @Test
    public void addOneRowItem() {...}

    @Test
    public void addTwoRowItem() {...}

    @Test(expected = RowItemsCountMoreThanAvailableColumnsException.class)
    public void addTwoRowItemsIntoTableWithOneColumnWillThrowException() {...}

    @Test(expected = IllegalArgumentException.class)
    public void addRowItemWithoutValueWillThrowException() {...}
...
}


Действия веду в правильном направлении???

Нужно ли писать два метода: который добавляет один элемент и два или более? Или же можно сразу написать метод который добавляет несколько элементов и проверить корректность?

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


Ну и вторая часть:
Этот мой класс при работе использует некий другой объект. И для проверки правильности отработки метода, приходиться писать вот такую шнягу
Код: java
1.
assertEquals(0, grid.getRows().getChildren().get(0).getChildren().size());


Хотел использовать моки, но не смог понять как проверять такого рода вещи.
Например добавление одной ячейки в строку выглядит вот так
Код: java
1.
2.
3.
4.
5.
6.
        actualRow = new Row();
        Cell cell = new Cell();
        Label label = new Label(cellData);
        label.setParent(cell);
        cell.setParent(actualRow);
        actualRow.setParent(rows);


и как проверить что метод сделал что должен, я просто не понимаю.
пока не придумал как иначе, приходится делать вот так
Код: java
1.
assertEquals("CellData1", ((Label) grid.getRows().getChildren().get(0).getChildren().get(0).getChildren().get(0)).getValue());

но это же ппц :(


-----
Если дела идут плохо, есть вероятность, что в ближайшее время они пойдут ещё хуже.(с)Мерфи
...
Рейтинг: 0 / 0
Помогите танкисту с TDD
    #38854233
For All
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Надо написать несколько отдельных тестов:
1. тест на Cell о том, что Label в этот Cell добавляется
2. тест на Row о том, что Cell в этот Row добавляется
2. тест на Table о том, что Row в этот Table добавляется
...
Рейтинг: 0 / 0
Помогите танкисту с TDD
    #38854584
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DDiver, я просто скажу несколько ИМХ.

Одна имха. Ты немножко зашёл далеко. Тест на интерфейс это ближе к контракту. Вообще в твоём
случае глядя на интерфейс TableBuilder совершенно невозможно придумать его поведение. Как он должен
добавлять RowItem. А должен ли вообще? Может он его фильтрует? Вобщем непонятно.

Вторая имха. Тест должен исходить из того что затраты на сам тест будут хотя-бы не более чем 20%
от затрат на кодинг самог вычислительно блока. Ну где-то как 80:20. Закон Парето вобщем-то.
В твоём случае получается где-то 55:45 вобщем полная лажа.

При таком подходе вероятность "запороть бок" в тесте практически такая-же как и в коде. Тоесть твой
тест в свою очередь тоже надо покрыть тестом который надо покрыть тестом.... и так далее.

Вобщем тестить надо ПРОСТЫМ образом СЛОЖНЫЕ чёрные ящики.

Усёк?
...
Рейтинг: 0 / 0
Помогите танкисту с TDD
    #38854590
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton Вторая имха. ....
Ну IMHO оно и на то и IMHO... Но я очень давно слышал кардинально другую точку зрения )))
...
Рейтинг: 0 / 0
Помогите танкисту с TDD
    #38854596
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Давай и другую точку зрения заслушаем. Чего уж тут елейничать.
...
Рейтинг: 0 / 0
Помогите танкисту с TDD
    #38854654
DDiver
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton,

По поводу первого ИМХА, это просто кусок интерфейса, тестирую я конечно же конкретную имплиментацию. Там методов больше и из-за этого более понятно что и для чего.

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

Для понимания, класс скрывает низкоуровневую работу с GUI элементом Grid, и позволяет просто и лаконично отрисовыать таблицу с шапкой любой сложности (это чисто для моих внутренних нужд)
Используя такой подход, я смог ни разу не запустив GUI написать этот класс, который с первого же раза заработал как нужно и без ошибок. Т.е. время на отлов ошибок в GUI я потратил на написание тестов.
Ещё один плюс, что я теперь спокойно могу что-то менять и рефакторить в классе, и после тестов быть полностью уверенным что всё работает и я ничего не сломал правками.
Честно сказать, писать тяжко, т.к. постоянно хочется что-то сразу реализовать с заделом на будущее, но по идеологии TDD нужно писать минимум, а потом уже рефакторить.

Неужели никто не использует такой подход? Или все пишут код, а потом уже какие-то тесты на него?
...
Рейтинг: 0 / 0
Помогите танкисту с TDD
    #38854659
scf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну я активно использую ТДД :-)
Правда, я склоняюсь больше к стилю BDD, так что буду писать со своей колокольни. Все ниженаписанное относится именно к юнит-тестам, интеграционные и приемочные оставим в стороне. Итак, исходя из примерно 10-летнего опыта коммерческой разработки на Java...

Общие соображения:
1. Тестировать имеет смысл в основном небольшие черные ящики. Если для теста требуется мок (или, еще хуже, несколько моков) - это либо ошибка дизайна, либо вы пытаетесь тестировать не логику, а glue код (который связывает между собой уже протестированные блоки.
Обоснование: Тесты имеет писать для кода, в котором высока вероятность ошибок и понятно поведение. Также тесты с моками хрупки и часто ломаются, т.к. зависят от большого кол-ва интерфейсов, а то и от реализаций.
2. 100% покрытие юнит-тестами - миф. После выполнения предыдущего пункта, стоимость (сложность написания и время, потраченное на исправление упавших тестов после доработок) юнит-тестов растет экспоненциально и они себя не окупают.
3. "Написание юнит-тестов улучшает структуру программы". Это верно, но верно без фанатизма. Структуру программы улучшают изолированные черные ящики со специфицированным входом и выходом. Также структуру программы улучшают маленькие методы, маленькие классы, минимум состояния в этих классах и разделение ответственности. Но если переборщить - то получается код, где всё построено на фабриках и интерфейсах (это придется делать, чтобы мОчить разные куски кода) . Его очень сложно понимать и поддерживать.

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

По второму примеру:
Этот API категории "сопля" выглядит ужасно. Я не совсем понимаю, как оно работает, но почему бы не сделать вот так:
Код: java
1.
grid.getRow(0).getColumnCount();


Если с API совсем-совсем ничего сделать нельзя, то я бы написал тест так:
Код: java
1.
2.
3.
4.
5.
6.
7.
assertEquals("CellData1", value(grid, 0, 0, 0));

private String value(Grid grid, int... ix) {
  Element e = grid.getRows();
  for (int i: ix) e = e.getChildren().get(i);
  return ((Label)e).getValue();
}


Или вообще придумал приспособление, которое проверяет всё дерево заголовков одним махом.

Еще умеет смысл глянуть вот сюда:
https://code.google.com/p/spock/ (для интернационалистов)
http://habrahabr.ru/post/137561/ (для патриотов)
...
Рейтинг: 0 / 0
Помогите танкисту с TDD
    #38855819
DDiver
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Спасибо за развернутый ответ.

С тестирование изолированных классов и поджиков всё понятно, но такое возможно только если всё пишешь сам. Но мы же знаем, что в реальности без сторонних библиотек и фрейморков, это мазохизм. Вот тут и появляется нужда в тестах с моками и прочими извращениями.
Например есть у нас некая библиотека, со страшно корявым и не выразительным API (но по каким-то причинам нужна именно она). Логично будет написать свой класс с нормальным API, который будет скрывать всю корявость и прочие потроха библиотеки.
Разработчик либы уже протестил свой код, а нам же нужно проверить, что мы его корректно вызываем. Но из-за корявости API просто замокать методы библиотечного класса не получиться, т.к. это жуткий overhead. Приходится использовать реальный класс из библиотеки и проверять результат работы нашего класса, дёргая методы этой библии и проверяя её внутреннее состояние, точно зная что мы должны получить при тех или иных манипуляциях.

С помощью какого ещё подхода можно такое проверить?
Это как мне кажется уже не совсем юнит тестирование, тут наверное ближе к интеграционному.
Где можно почитать об этом, учитывая специфику solo developer, т.е. когда ты сам себе и чтец, и жнец и на дуду игрец.
...
Рейтинг: 0 / 0
Помогите танкисту с TDD
    #38855850
scf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DDiver,

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

Хороших книг по TDD/BDD не знаю. Видел книги из серии "объясняю, что это такое", а дальше - только личный опыт.
...
Рейтинг: 0 / 0
Помогите танкисту с TDD
    #39004149
kmaw
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
scfТесты имеет писать для кода, в котором высока вероятность ошибок и понятно поведение

полностью согласен. и не могу придумать иные случаи, когда они нужны
...
Рейтинг: 0 / 0
Помогите танкисту с TDD
    #39004152
kmaw
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
и тем более, как можно разрабатывать на основе тестов - я тоже в танке
...
Рейтинг: 0 / 0
11 сообщений из 11, страница 1 из 1
Форумы / Java [игнор отключен] [закрыт для гостей] / Помогите танкисту с TDD
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]