Pull to refresh
23
0
Aleksandr Goida @ETman

Software Developer

Send message
Хотя, если все-таки рефакторинг сделали нормальный, то тест на публичный может быть тоже нормальным. Тут от многих факторов зависист.
Спасибо. В первой половине я рассматривал именно решение второй проблемы (как вы и сказали). Про идеальный вариант вы тоже написали (вынос в отдельный класс).

Со в торой частью согласен. Надо поработать над качеством изложения, т.к. много осталось «за кадром».
Мне нравится ваше решение. Но есть нюанс. Такие изменения слишком большие для задачи. Т.е. как задача по техническому долгу она отличная и, когда будет одобрена, оно будет примерно так и решено. Но сейчас надо внести минимум изменений. Я умышлено помещаю ситуацию в условия, когда у вас времени не вагон, и надо все сделать так, чтобы на это можно было опираться в дальнейшем и это не вызывало головной боли у других разработчиков.

Как вы объясните зачем нужны такие большие изменения ради одного флага?
Реалии большинства проектов такие, что там костыль на костыле и костылем погоняет. Можно не обсуждать. А я вижу проблему, что слишком много внимания уделяется идеальному коду и коротким проектам, где с нуля создается идеальная архитектура и идеально пишутся тесты. И всё что не так: говнокод и костыли. Хотя этого 80% (а то и больше) от всего общего количества кода. Мне хочется донести, что бояться писать тесты не надо. Но идеалистический подход и отношение к этому приводят к тому, что многим сложно в голове уместить идею юнит-тестирования. И подходят к ним, скорее, как к еще одному продакшн коду. Когда цель их в другом.
Возможно я недостаточно описал, что в примере я не обсуждаю ситуацию из разряда «если бы». Как должно быть, понятно и об этом написано очень много других статей. Вы аппелируете к идеальному коду, когда есть возможность всё сделать, как надо. А я рассказываю о более реальной ситуации, когда есть говно-код, и все равно надо с ним работать и его тестировать. Это, конечно, не тот идеальный TDD, о котором идет речь у классиков, но это тоже написание тестов перед тем, как пишется сам функционал. Отличие в том, что вместо «писать сразу на имеющийся public» следует сесть и подумать о том, стоит ли овца выделки. Если тест для публичного метода, написан через workaround'ы и рефакторинг, сделаный под этот тест, то это плохой тест. Думаю, если он упадёт, еще и дебаг понадобится, чтобы понять что пошло не так.

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

Относительно internal. Да, какая-то логика становится видна для тестов. Но это не страшно, т.к. тесты легкие и понятные. Если начали падать, то понятно почему. Если стали неактуальны — удаляем и пишем другие. Кроме того, internal — это еще не public. Internal не является хинтом, что этот метод должен быть использован везде, где можно. Кроме того, обычно в команде на этапе Code Review пресекаются неправльные использования. Да, это не идеальный TDD, но и громоздить код в настройках юнит-тестов публичных методов, и заниматься рефакторингом, по сути, ради рефакторинга, нет необходимости.
Согласен, код плохой. Но вот он такой. Это часто в долгоживущих проектах, где код писался 10ю разными разработчиками. А тестировать все равно надо. Если переписать и исправить, то будет лучше. Но в реальности, это редко когда возможно. К сожалению.
Можно проще, как я написал. Зачем так извращаться? Это должен быть не интеграционный тест, а юнит-тест. Простой и быстрый.
Вам надо написать первый тест. Других нет.
Так просто не получится, потому что основной код выполняется параллельно и завершится позже выполнения assert-ов в тесте. Вам нужно после 3) ждать завершения созданных потоков, но в приведенном примере, без изменений вы это сделать не можете.
Та же фигня. Ситуация вообще до смешного доходит. Были самопроизвольно подключены услуги смени гудок и кто звонил. При этом последнюю я специально просил отключить при покупке сим карты в офисе и проверил там же, чтобы она была отключена. Вечером того же дня, полез проверять на всякий случай услуги, зная, такое может быть, что снова что-то подключится. Убедившись, что всё нормально, закрываю ЛК… и тут приходят смс о подключении на выше указанные услуги. После я переписывался с поддержкой, но сумму вернули. Остается осадок, что необхоимо постоянно проверять ситуацию в ЛК.
хороший пример проблемы.
Цель — обеспечить качество кода, когда изменения делаются не в самом тестируемом классе, а в используемых им других классах.

То, что вы описываете с хелперами, это как написание еще одного продакшн кода. Потом понадоятся тесты для хелперов, чтобы проверить, что они правильно работают.
Конкретная реализация может быть сложной и приводить к большому усложнению тестирования публичных методов. Если вы стараетесь не изменять существующие классы, а больше руководтствоваться OCP, то проблема, о которой вы пишете, резко снизится. «При изменеии внутренней структуры» тесты далжны быть легко выкинуты и написаны заного. В этом и состоит задача тестов и TDD: быть простыми и легкими, как в понимании, так и в обращении.

Хелперы — это палка с двумя концами. Один помогает, другой бьет по башке. Когда у вас есть лес классов из хелперов и непонятно, какой в вашем случае подходит, вы просто напишете новый. В итоге где-то в тестах что-то начинает валиться и вы тратите время на долгий и нужный дебаг тестов. Что опять, на мой взгляд, не соответвует идее TDD.

Но я не говорю тут об интеграционных тестах.
А если рассмотреть вариант с другой стороны:
  • есть метод, не являющийся методом интерфейса класса, но выполняющий нетривиальную логику.
  • покрываешь его тестами так, чтобы быть уверенным в его 100% работе в известных случаях.
  • в публичном методе есть логика вызова этого метода, которую ты покрываешь (и только)

Знаете технику Sprout Method? Это оно и есть.

Ваш основной public-метод генерирует множество входящих значений параметров для непубличного метода. Вы проверятете не каждое значение, а то, что это множество правильно передается в непубличный метод. А непубличный метод вы проверяете тпо всему множеству передаваемых значений (по каждому важному). В итоге вам не надо писать 8 тестов для непубличного метода и 8 тестов для публичного. Для публично, в зависимости от логики, может оказаться достаточным, например, только 2.
ну, только если «рефлексия» в смысле «опять не понятно почему этот юнит-тест падает»? ;)
Т.е. вы не только противоречите общепринятым нормам, но ещё и просите у общественности помощи в свержении норм???

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

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

Но когда у вас есть 10 таких тестов, и 5 из них падает с NullRef exception, в том месте, где не должно этого было быть, вам остается только сидеть и дебажить сами тесты. Это в корне, на мой взгляд, не соответствует идее TDD, согласно которой тесты должны быть простыми и ясными.
Спасибо. Я соглашусь со всем, что Вы сказали, но как обычно «дьявол кроется в деталях». Я не занимаюсь именно руководством команд, но замечаю, иногда, такую вещь: объяснение «почему» что-то необходимо делать сталкивается с таким препятствием, как «необразованность». Я имею ввиду тут не буквальную необразованность людей, а совокупость нескольких или одного фактора: нехватка информации, знаний, практики или опыта. В итоге получается, что предлагаемое решение не является достаточным с точки зрения качества. Либо человеку нужна информация, которая для работы над задачей вовсе необязательна, но у него есть убеждение, что она критична. Если пытаться это всё выравнивать сразу, без большого авторитета, то кредит доверия растратится очень быстро. Даже если ты на 100500% прав и они сами потом убедятся в этом. Тут, как мне кажется, необходимы именно soft skills.
На моём «неграмотном» языке я это для себя формулирую, как принятие команды и всех рисков вместе с ней. Коротко говоря, «пусть как хотят, так и делают», главное, чтобы цель была достигнута без «кровавых» ошибок. На ошибках и шишках народ сам научится. А если не научится, то просто такая команда (вместе с руководителем). Но, возможно, во мне это говорят артефакты «эксперта» и неопытность, как руководителя.
Только одна тема не раскрыта, хотя, считаю, она просто не поместится в рамки такой статьи о том, как заработать авторитет в команде, если ты был назначен руководителем.

Information

Rating
Does not participate
Location
Lozenets, Sofiya, Болгария
Date of birth
Registered
Activity