Использование класса friend или добавление аксессуаров для модульного тестирования на С++?

Лучше ли добавлять функции, возвращающие внутреннее состояние объекта для модульного тестирования, в отличие от того, чтобы сделать класс тестирования другом? - особенно, когда нет функций для функций, кроме случаев модульного тестирования.

Ответ 1

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

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

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

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

Ответ 2

Я не соглашусь с принятым ответом и вместо этого рекомендую использовать класс друзей.

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

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

Ответ 3

Использование классов друзей для модульного тестирования является совершенно законным и позволяет поддерживать инкапсуляцию. Вы не должны изменять свой открытый интерфейс классов просто для того, чтобы сделать класс более надежным. Подумайте об этом таким образом. Что, если вы приобрели стороннюю библиотеку FTP, и вы пытаетесь ее использовать, а публичный интерфейс загроможден множеством методов, о которых вам даже не нужно знать просто из-за модульных тестов! Даже изменение защищенного интерфейса для компенсации единичных тестов - BAD. Если я наследую от какого-то класса, я не хочу беспокоиться о том, какие методы мне полезны и какие из них существуют только из-за модульных тестов!!! Использование классов друзей для модульных тестов помогает вам поддерживать простой, простой в использовании интерфейс класса; это помогает сохранить инкапсуляцию и абстракцию!!!

Я слышал, что использование классов друзей для модульного тестирования плохо, потому что тестируемый класс не должен быть "тесно связан" с его тестовым классом, и он не должен "знать" что-либо о своем тестовом классе. Я не покупаю это. Это одна строка добавлена ​​в верхнюю часть класса:

класс друзей MyClassTest;

и теперь вы можете протестировать свой класс так, как хотите!

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

Ответ 4

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

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

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

Ответ 5

Как сделать внутреннее состояние "защищенным"? А затем выполните unittest с использованием производного класса.

Ответ 6

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

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

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