Если у вас есть только перечисление со значениями (нет методов, которые можно было бы сделать в Java), и это перечисление является частью бизнес-определения системы, следует ли писать для него модульные тесты?
Я думал, что они должны быть написаны, даже если они могут показаться простыми и избыточными. Я считаю, что то, что касается бизнес-спецификации, должно быть явно написано в тесте, будь то с помощью unit /gration / ui / и т.д. тесты или с использованием системы типов языка в качестве метода тестирования. Поскольку значения, которые должен иметь enum (например, в Java), с точки зрения бизнеса, не могут быть протестированы с использованием системы типов, я думаю, что для этого должен быть модульный тест.
Этот вопрос не похож на этот, поскольку он не решает ту же проблему, что и мой. В этом вопросе есть бизнес-функция (savePeople), и человек интересуется внутренней реализацией (forEach). Там есть средний бизнес-уровень (функция спасения людей), инкапсулирующий языковую конструкцию (forEach). Здесь языковая конструкция (enum) используется для определения поведения с точки зрения бизнеса.
В этом случае детали реализации совпадают с «истинной природой» данных, то есть набором (в математическом смысле) значений. Возможно, вы могли бы использовать неизменный набор, но там должны присутствовать те же значения. Если вы используете массив, то же самое необходимо сделать для проверки бизнес-логики. Я думаю, что загадка здесь заключается в том, что языковая конструкция очень хорошо совпадает с природой данных. Я не уверен, правильно ли я объяснил
источник
Ответы:
Нет, они просто государственные.
По сути, тот факт, что вы используете enum - это деталь реализации ; это то, что вы можете захотеть изменить в другой дизайн.
Проверка перечислений на полноту аналогична проверке наличия всех представимых целых чисел.
Однако проверка поведения, поддерживаемого перечислениями, является хорошей идеей. Другими словами, если вы начнете с проходного набора тестов и закомментируете какое-либо одно значение перечисления, то по крайней мере один тест должен провалиться (ошибки компиляции считаются ошибками).
источник
Hearts
,Spades
,Diamonds
,Clubs
] если Вы когда-нибудь карту, если карта красная / черная?null_ptr
ошибку. Теперь это имеет код ошибки через enum. Код, проверяющий на наличиеnull_ptr
ошибок, ищет код и через enum. Так что это может иметь значение5
(например). Теперь вам нужно добавить еще один код ошибки. Перечисление изменено (допустим, мы добавили новое в начало перечисления). Значениеnull_ptr
теперь6
. Это проблема? Теперь вы возвращаете код ошибки6
и проверяете6
. Пока все логически непротиворечиво, у вас все хорошо, несмотря на то, что это изменение нарушает ваш теоретический тест.Вы не проверяете объявление enum . Вы можете проверить, имеет ли функция ввода / вывода ожидаемые значения перечисления. Пример:
Вы не пишете тесты, проверяющие, тогда enum
Parity
определяет именаEven
иOdd
. Такой тест был бы бессмысленным, поскольку вы просто повторяли бы то, что уже указано в коде. Сказать одно и то же дважды не значит более правильно.Вы делаете тесты записи проверочных
GetParity
слова будут возвращатьEven
на 0,Odd
для 1 и так далее. Это ценно, потому что вы не повторяете код, вы проверяете поведение кода независимо от реализации. Если код внутриGetParity
был полностью переписан, тесты все равно были бы действительными. Действительно, основными преимуществами модульных тестов является то, что они дают вам возможность безопасно переписывать и реорганизовывать код, гарантируя, что код по-прежнему работает, как и ожидалось.Но если у вас есть тест, который гарантирует, что объявление enum определяет ожидаемые имена, то любое изменение, которое вы сделаете в enum в будущем, потребует от вас также изменить тест. Это означает, что это не просто вдвое больше работы, это также означает, что любая выгода от модульного теста потеряна. Если вам необходимо изменить код и выполнить тестирование одновременно , то защиты от ошибок не существует.
источник
Если есть риск, что изменение enum нарушит ваш код, тогда, конечно, все, что с атрибутом [Flags] в C # будет хорошим случаем, потому что добавление значения между 2 и 4 (3) будет побитовым 1 и 2, а не сдержанный предмет.
Это слой защиты.
Вы должны подумать о том, чтобы иметь кодекс практики enum, с которым знакомы все разработчики. Не полагайтесь на то, что текстовые представления перечисления являются общими, но это может противоречить вашим правилам сериализации.
Я видел, как люди «исправляли» заглавные буквы в записях enum, сортировали их по алфавиту или по какой-то другой логической группировке, которая порвала другие биты плохого кода.
источник
Нет, проверка, проверяющая, что перечисление содержит все допустимые значения и ничего более, по сути, не повторяет объявление перечисления. Вы бы только проверяли, что язык правильно реализует конструкцию enum, которая является бессмысленным тестом.
При этом вы должны проверить поведение, которое зависит от значений перечисления. Например, если вы используете значения перечисления для сериализации сущностей в json или чего-либо еще или сохраняете значения в базе данных, вы должны проверить поведение для всех значений перечисления. Таким образом, если перечисление изменено, по крайней мере, один из тестов должен провалиться. В любом случае, то, что вы будете тестировать, - это поведение вокруг вашего перечисления, а не само объявление перечисления.
источник
Ваш код должен работать правильно, независимо от фактических значений перечисления. Если это так, то никаких модульных тестов не требуется.
Но у вас может быть код, в котором изменение значения перечисления может привести к поломке. Например, если значение enum хранится во внешнем файле, и после изменения значения enum чтение внешнего файла даст неправильный результат. В этом случае у вас будет БОЛЬШОЙ комментарий рядом с перечислением, предупреждающий любого не изменять никакие значения, и вы вполне можете написать модульный тест, который проверяет числовые значения.
источник
В общем, просто проверка того, что перечисление имеет жестко запрограммированный список значений, не имеет большого значения, как говорили другие ответы, потому что тогда вам просто нужно обновить test и enum вместе.
Однажды у меня был случай, когда один модуль использовал перечисления типов из двух других модулей и отображал их между собой. (У одного из перечислений была дополнительная логика, у другого был доступ к БД, у обоих были зависимости, которые должны быть изолированы друг от друга.)
В этом случае я добавил тест (в модуле отображения), который проверял, что все записи перечисления в исходном перечислении также существуют в целевом перечислении (и, следовательно, что сопоставление всегда будет работать). (В некоторых случаях я проверял и наоборот)
Таким образом, когда кто-то добавил запись enum к одному из перечислений и забыл добавить соответствующую запись к другому, тест начал проваливаться.
источник
Перечисления - это просто конечные типы с собственными (надеюсь значащими) именами. Перечисление может иметь только одно значение, например,
void
которое содержит толькоnull
(некоторые языки называют этоunit
и используют имяvoid
для перечисления без элементов!). Может иметь два значения, например,bool
которое имеетfalse
иtrue
. Может быть три, какcolourChannel
сred
,green
иblue
. И так далее.Если два перечисления имеют одинаковое количество значений, то они «изоморфны»; то есть, если мы систематически переключаем все имена, то мы можем использовать одно вместо другого, и наша программа не будет вести себя по-другому. В частности, наши тесты не будут вести себя иначе!
Например,
result
содержаниеwin
/lose
/draw
изоморфно вышеприведенномуcolourChannel
, поскольку мы можем заменить, например,colourChannel
наresult
,red
сwin
,green
сlose
иblue
сdraw
и до тех пор, пока мы делаем это везде (производители и потребители, анализаторы и сериализаторы, записи базы данных, файлы журналов и т. Д. ) тогда не будет никаких изменений в нашей программе. Любые «colourChannel
тесты», которые мы написали, все равно пройдут, хотя их больше нетcolourChannel
!Кроме того, если перечисление содержит более одного значения, мы всегда можем переставить эти значения, чтобы получить новое перечисление с тем же числом значений. Поскольку число значений не изменилось, новое расположение изоморфно старому, и, следовательно, мы могли бы отключить все имена, и наши тесты все равно бы прошли (обратите внимание, что мы не можем просто переключить определение; мы должны все еще отключите все сайты использования также).
Это означает, что для машины перечисления являются «различимыми именами» и ничем иным . Единственное, что мы можем сделать с перечислением, это определить, являются ли два значения одинаковыми (например,
red
/red
) или разными (например,red
/blue
). Так что это единственное, что может сделать «модульный тест», напримерКак говорит @ jesm00, такой тест проверяет реализацию языка, а не вашу программу. Эти тесты никогда не являются хорошей идеей: даже если вы не доверяете языковой реализации, вы должны тестировать ее извне , поскольку нельзя доверять правильному запуску тестов!
Такова теория; как насчет практики? Основная проблема, связанная с такой характеристикой перечислений, заключается в том, что программы «реального мира» редко бывают автономными: у нас есть устаревшие версии, удаленные / встроенные развертывания, исторические данные, резервные копии, действующие базы данных и т. Д., Поэтому мы никогда не сможем «отключиться» все вхождения имени, не пропуская некоторые использования.
Однако такие вещи не являются «обязанностью» самого перечисления: изменение перечисления может нарушить связь с удаленной системой, но, наоборот, мы могли бы решить такую проблему, изменив перечисление!
В таких случаях, перечисление является красно-селедка: что если одна система нуждается в этом , чтобы быть этот путь, и еще нужно, чтобы это было что путь? Это не может быть и то и другое, независимо от того, сколько тестов мы пишем! Настоящим виновником здесь является интерфейс ввода / вывода, который должен производить / потреблять четко определенные форматы, а не «любое целое число, которое выбирает интерпретатор». Таким образом, реальным решением является тестирование интерфейсов ввода / вывода : с помощью модульных тестов, чтобы проверить, анализирует ли он / печатает ли ожидаемый формат, и с помощью интеграционных тестов, чтобы проверить, что формат действительно принят другой стороной.
Мы все еще можем задаться вопросом, достаточно ли тщательно прорабатывается перечисление, но в этом случае перечисление снова представляет собой красную сельдь. На самом деле нас беспокоит сам набор тестов . Мы можем обрести уверенность здесь несколькими способами:
red
, а мы только тестируемred
, то мы имеем 100% охват. Свойство шашка будет (пытаться) генерировать контрпримеры наших утверждений, например, генерируяgreen
иblue
ценность , которые мы забыли проверить.источник
Нет. Юнит-тесты предназначены для тестирования юнитов.
https://en.wikipedia.org/wiki/Unit_testing
Автоматизированный тест для объявленного перечисления будет проверять целостность языка и платформы, на которой он работает, а не логику в коде, созданном разработчиком. Это не будет служить никакой полезной цели - документация включена, поскольку код, объявляющий перечисление, служит как документация, так и код, который будет его проверять.
источник
Ожидается, что вы протестируете наблюдаемое поведение вашего кода, влияние вызовов методов / функций на наблюдаемое состояние. Пока код работает правильно, с вами все в порядке, вам не нужно ничего проверять.
Вам не нужно явно утверждать, что у типа enum есть ожидаемые вами записи, точно так же, как вы явно не утверждаете, что класс действительно существует или что у него есть ожидаемые методы и атрибуты.
На самом деле, тестируя поведение, вы неявно утверждаете, что классы, методы и значения, участвующие в тесте, существуют, поэтому вам не нужно явно это утверждать.
Обратите внимание, что вам не нужны значимые имена для вашего кода, чтобы делать правильные вещи, это просто удобство для людей, читающих ваш код. Вы можете заставить свой код работать с перечисляемыми значениями вроде
foo
,bar
... и такими методамиfrobnicate()
.источник