Изучая передовые практики модульного тестирования, которые помогут собрать рекомендации для моей организации, я столкнулся с вопросом о том, лучше или полезно разделять контрольные приборы (тестовые классы) или хранить все тесты для одного класса в одном файле.
Кстати, я имею в виду «модульные тесты» в чистом смысле, что они представляют собой тесты «белого ящика», нацеленные на один класс, одно утверждение на тест, все проверенные зависимости и т. Д.
Примером сценария является класс (назовите его Document), который имеет два метода: CheckIn и CheckOut. Каждый метод реализует различные правила и т. Д., Которые контролируют их поведение. Следуя правилу «одно утверждение на тест», у меня будет несколько тестов для каждого метода. Я могу поместить все тесты в один DocumentTests
класс с такими именами, как CheckInShouldThrowExceptionWhenUserIsUnauthorized
и CheckOutShouldThrowExceptionWhenUserIsUnauthorized
.
Или я мог бы иметь два отдельных тестовых класса: CheckInShould
и CheckOutShould
. В этом случае имена моих тестов будут сокращены, но они будут организованы так, чтобы все тесты для определенного поведения (метода) были вместе.
Я уверен, что есть «за» и «против» для любого подхода, и мне интересно, прошел ли кто-нибудь путь с несколькими файлами, и если да, то почему? Или, если вы выбрали подход с одним файлом, почему вы чувствуете, что он лучше?
источник
testResponseContainsSuccessTrue()
,testResponseContainsMyData()
аtestResponseStatusCodeIsOk()
. Вы бы их в один ,testResponse()
который три утверждающей:assertEquals(200, response.status)
,assertEquals({"data": "mydata"}, response.data)
иassertEquals(true, response.success)
Ответы:
Это редко, но иногда имеет смысл иметь несколько тестовых классов для данного тестируемого класса. Как правило, я делаю это, когда требуются разные настройки, и они распределяются по подмножеству тестов.
источник
На самом деле не вижу убедительной причины, по которой вы бы разбили тест для одного класса на несколько классов. Поскольку идея вождения должна заключаться в поддержании сплоченности на уровне класса, вы должны стремиться к этому и на уровне теста. Просто несколько случайных причин:
источник
Если вы вынуждены разделять модульные тесты для класса по нескольким файлам, это может указывать на то, что сам класс плохо спроектирован. Я не могу представить ни одного сценария, в котором было бы более выгодно разделить модульные тесты для класса, который разумно придерживается принципа единой ответственности и других передовых методов программирования.
Кроме того, допустимо иметь более длинные имена методов в модульных тестах, но если это вас беспокоит, вы всегда можете переосмыслить соглашение об именовании модульных тестов, чтобы сократить имена.
источник
Один из моих аргументов против разделения тестов на несколько классов состоит в том, что другим разработчикам в команде становится труднее (особенно тем, кто не так разбирается в тестах) найти существующие тесты ( интересно, есть ли уже тест для этого Метод? Интересно, где это будет? ), а также где поставить новые тесты ( я собираюсь написать тест для этого метода в этом классе, но не совсем уверен, должен ли я поместить их в новый файл или существующий один? )
В случае, когда разные тесты требуют радикально разных настроек, я видел, как некоторые специалисты по TDD помещали «приспособление» или «настройку» в разные классы / файлы, но не в сами тесты.
источник
Хотел бы я вспомнить / найти ссылку, где техника, которую я выбрал, была впервые продемонстрирована. По сути, я создаю отдельный абстрактный класс для каждого тестируемого класса, который содержит вложенные тестовые таблицы (классы) для каждого тестируемого члена. Это обеспечивает изначально желаемое разделение, но сохраняет все тесты в одном файле для каждого местоположения. Кроме того, это генерирует имя класса, которое позволяет легко группировать и сортировать в тестовом средстве.
Вот пример того, как этот подход применяется к моему первоначальному сценарию:
В результате в списке тестов появляются следующие тесты:
По мере добавления новых тестов они легко группируются и сортируются по имени класса, что также сохраняет все тесты для тестируемого класса вместе.
Еще одним преимуществом этого подхода, который я научился использовать, является объектно-ориентированная природа этой структуры. Это означает, что я могу определять код внутри методов запуска и очистки базового класса DocumentTests, который будет использоваться всеми вложенными классами, а также внутри каждого из них. вложенный класс для тестов, которые он содержит.
источник
Попробуйте подумать об обратном на минуту.
Почему у вас есть только один тестовый класс на класс? Вы делаете классный тест или модульный тест? Вы вообще зависите от занятий ?
Под модульным тестом подразумевается тестирование определенного поведения в определенном контексте. Тот факт, что у вашего класса уже есть
CheckIn
средство, должно быть такое поведение, которое в первую очередь нуждается в нем.Как бы вы подумали об этом псевдокоде:
Теперь вы не тестируете
checkIn
метод напрямую . Вместо этого вы тестируете поведение (которое, к счастью, регистрируется;)), и если вам нужно провести рефакторингDocument
и разделить его на другие классы или объединить в него другой класс, ваши тестовые файлы по-прежнему являются связными, они по-прежнему имеют смысл, поскольку Вы никогда не меняете логику при рефакторинге, только структуру.Один тестовый файл для одного класса просто усложняет рефакторинг, когда вам это нужно, и тесты также имеют меньший смысл с точки зрения предметной области / логики самого кода.
источник
В общем, я бы рекомендовал думать о тестах как о тестировании поведения класса, а не метода. Т.е. некоторым вашим тестам может потребоваться вызвать оба метода в классе, чтобы проверить ожидаемое поведение.
Обычно я начинаю с одного класса модульных тестов для каждого производственного класса, но в конечном итоге могу разделить этот класс модульных тестов на несколько классов тестов на основе поведения, которое они тестируют. Другими словами, я бы рекомендовал не разбивать тестовый класс на CheckInShould и CheckOutShould, а скорее разбивать по поведению тестируемого модуля.
источник
1. Подумайте, что может пойти не так
На начальном этапе разработки вы хорошо знаете, что делаете, и оба решения, вероятно, будут работать нормально.
Это становится более интересным, когда тест не проходит после изменения намного позже. Есть две возможности:
CheckIn
(илиCheckOut
). Опять же, в этом случае все в порядке как с одним файлом, так и с двумя файлами.CheckIn
иCheckOut
(и, возможно, их тесты) способом, который имеет смысл для каждого из них, но не для обоих вместе. Вы нарушили согласованность пары. В этом случае разделение тестов на два файла усложнит понимание проблемы.2. Рассмотрим, для чего используются тесты
Тесты служат двум основным целям:
Так?
Обе эти перспективы предполагают, что совместное проведение тестов может помочь, но не повредит.
источник