Использование класса друга или добавление методов доступа для модульного тестирования в C ++? - PullRequest
11 голосов
/ 19 июля 2009

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

Ответы [ 6 ]

12 голосов
/ 19 июля 2009

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

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

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

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

9 голосов
/ 19 июля 2009

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

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

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

3 голосов
/ 13 ноября 2010

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

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

класс друга MyClassTest;

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

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

1 голос
/ 19 июля 2009

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

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

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

0 голосов
/ 19 июля 2009

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

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

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

0 голосов
/ 19 июля 2009

Как насчет сделать внутреннее состояние "защищенным"? А затем выполните юнит-тест, используя производный класс.

...