Это в порядке для изменения видимости метода ради поблочного тестирования?

Много раз я нахожу меня порванным между созданием метода частный, чтобы препятствовать тому, чтобы кто-то назвал его в контексте, который не имеет смысла (или завинтил бы внутреннее состояние включенного объекта), или обнародовать метод (или обычно внутренний) для представления его блоку модульного теста. Я просто задавался вопросом, что сообщество Переполнения стека думало об этой дилемме?

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

В последнее время я склонялся к тестируемости, поскольку большая часть кода только будет усиленной небольшой группой разработчиков, но я думал, что буду видеть то, что все остальные думали?

38
задан TrueWill 25 February 2010 в 02:56
поделиться

5 ответов

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

Однако, если метод не является / не должен быть частью общедоступного API, и он не вызывается другими типами, внутренними по отношению к сборке, НЕ тестируйте его напрямую.Он должен быть защищенным или частным, и его следует тестировать только косвенно путем модульного тестирования вашего общедоступного API. Если вы пишете модульные тесты для непубличных (или тех, что должны быть непубличными) членов ваших типов, вы привязываете тестовый код к внутренним деталям реализации.

Это плохой вид связи, увеличивает количество необходимых модульных тестов, увеличивает рабочую нагрузку как в краткосрочной перспективе (больше модульных тестов), так и в долгосрочной перспективе (больше поддержки тестов и модификаций в ответ на рефакторинг внутренней реализации. подробности). Еще одна проблема с тестированием непубличных членов состоит в том, что вы тестируете код, который на самом деле может не понадобиться или не использоваться. ОТЛИЧНЫЙ способ найти мертвый код - это когда он не покрывается ни одним из ваших модульных тестов, когда ваш общедоступный API покрывается на 100%. Удаление мертвого кода - отличный способ сохранить вашу базу кода компактной и средней, и это невозможно, если вы не будете осторожны с тем, что вы вкладываете в свой общедоступный API, и какие части вашего кода вы тестируете.

РЕДАКТИРОВАТЬ: В качестве небольшого дополнительного примечания ... с правильно разработанным общедоступным API вы можете очень эффективно использовать такой инструмент, как Microsoft PEX , для автоматического создания модульных тестов с полным покрытием, которые протестируйте каждый путь выполнения вашего кода. В сочетании с несколькими вручную написанными тестами, охватывающими критическое поведение, все, что не охвачено, можно считать мертвым кодом и удалить, и вы можете значительно сократить процесс модульного тестирования.

16
ответ дан 27 November 2019 в 03:52
поделиться

Знаете ли вы раньше времени, что карта с id = = 1 является второй картой в вашем векторе? Если это так:

user> (-> my-vec
          (assoc-in [1 :a] "baz2")
          (assoc-in [1 :b] "spam2"))
[{:id 0, :a "foo", :b "bar"} {:id 1, :a "baz2", :b "spam2"} {:id 2, :a "qux", :b "fred"}]

Если вам нужно получить доступ к вашим данным по идентификатору много, другая идея состоит в том, чтобы заменить ваш вектор хеш-карт на хеш-карту хеш-карт с клавиатуры на : id . Тогда вы можете легче assoc-in независимо от порядка вещей.

user> (def new-my-vec (zipmap (map :id my-vec) my-vec))
#'user/new-my-vec
user> new-my-vec
{2 {:id 2, :a "qux", :b "fred"}, 1 {:id 1, :a "baz", :b "spam"}, 0 {:id 0, :a "foo", :b "bar"}}
user> (-> new-my-vec
          (assoc-in [1 :a] "baz2")
          (assoc-in [1 :b] "spam2"))
{2 {:id 2, :a "qux", :b "fred"}, 1 {:id 1, :a "baz2", :b "spam2"}, 0 {:id 0, :a "foo", :b "bar"}}
-121--2809803-

Действительно следует использовать qsort (в языке C # include < stdlib.h > ) или std:: sort (в языке C++, # include < алгоритм > ) вместо такой сортировки пузырей. Если это C++ и вы принимаете совет @ T.E.D. использовать std:: Последовательности вместо необработанного C последовательности, вам даже не нужно указывать сравнение, потому что оператор < будет использоваться и будет поступать правильно.

-121--3210335-

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

Вы используете C # да? Извлеките внутренние элементы , видимые в классе атрибутов . Можно объявить проверяемые методы внутренними и предоставить узлу тестирования установки доступ к внутренним устройствам.

23
ответ дан 27 November 2019 в 03:52
поделиться

Это обычная мысль.

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

Ответы на этот вопрос (Java) и этот вопрос (.NET) должны быть полезными.

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

2
ответ дан 27 November 2019 в 03:52
поделиться

В целом я согласен с @jrista. Но, как обычно, все зависит от ситуации.

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

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

Так что для устаревшего кода делайте то, что должны делать.

1
ответ дан 27 November 2019 в 03:52
поделиться

В .NET вы должны использовать Accessors для модульного тестирования, даже вместо атрибута InternalsVisibleTo. Аксессоры позволяют получить доступ к любому методу в классе, даже если он является частным. Они даже позволяют тестировать абстрактные классы, используя пустой фиктивный производный объект (см. Класс «PrivateObject»).

В основном в вашем тестовом проекте вы используете класс средств доступа, а не реальный класс с методами, которые хотите протестировать. Класс средств доступа такой же, как и «настоящий» класс, за исключением того, что все является общедоступным для вашего тестового проекта. Visual Studio может сгенерировать для вас аксессоры.

НИКОГДА не делайте тип более заметным, чтобы облегчить модульное тестирование.

IMO НЕПРАВИЛЬНО говорить, что вы не должны тестировать частные методы. Модульные тесты имеют исключительную ценность для регрессионного тестирования, и нет причин, по которым частные методы не должны подвергаться регрессионному тестированию с помощью детальных модульных тестов.

0
ответ дан 27 November 2019 в 03:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: