Как сделать один тест зависимым от результатов другого теста?

13

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

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

Например, у меня есть утилита для разделения сообщений, которая используется (или, скорее, ее выводом) анализатором сообщений. Я хотел бы убедиться, что разделитель сообщений работает правильно, прежде чем анализатор сообщений будет проверен.

Я написал тесты для них обоих, но есть ли способ связать их и сделать один тест зависимым от результата другого теста?

Я не смог найти подходящий тег для этого, но я использую модуль модульного тестирования Visual Studio.

t3chb0t
источник
1
Я понимаю, что анализатор не работает правильно, если утилита не работает. Но если вы запустите свои тесты, вы увидите, что служебные тесты не пройдены. Почему вы хотите, чтобы другие тесты тоже не сработали?
Евгений Мартынов
1
Я никогда не слышал о том, чтобы кто-то хотел этого раньше. Что вы пытаетесь достичь?
Эсбен Сков Педерсен
Я использую некоторые функции утилиты для подготовки данных к тестам синтаксического анализатора, поэтому я хотел бы быть абсолютно уверенным, что утилита работает правильно, прежде чем что-либо тестировать.
t3chb0t
3
@ t3chb0t Если вы хотите убедиться, что ваша утилита работает, вам нужно написать модульные тесты для проверки вашей утилиты. Модульные тесты должны быть атомными. Вы только хотите, чтобы они протестировали один компонент.
maple_shaft

Ответы:

11

Нет смысла следить за тем, чтобы каждый дефект в вашей системе отключал ровно один тест.

У набора тестов есть одно задание: проверять отсутствие известных дефектов. Если есть дефект, не имеет значения, если один тест не пройден или 10. Если вы привыкнете к тому, что ваш набор тестов провалился, если вы попытаетесь оценить, насколько «плоха» ваша программа, подсчитав неудачные тесты, вы не используя регрессионное тестирование в правильном направлении. Набор тестов должен пройти все тесты, прежде чем публиковать код.

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

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

Килиан Фот
источник
8

Это зависит от вашего инструментария, но вы, вероятно, не можете (и не должны)

Некоторые платформы модульного тестирования ( например, PHPUnit ) позволяют вам «цеплять» тесты, чтобы неудачный тест на одном уровне не выполнял другие тесты. Однако я сомневаюсь, что это решит вашу проблему в этой ситуации.

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

Вы можете поместить эти служебные методы в отдельное решение или категорию тестирования. Убедитесь, что они визуально «выделяются» в вашем тестовом средстве, или что эта категория запускается первой и не запускает никаких других тестов, если тесты в этой категории не пройдены *. При сбое одного из этих тестов сбой, вероятно, будет касаться всех тестов, и вам следует убедиться, что тот, кто запускает тесты, знает, что нужно начинать, прежде всего исправляя эти неудачные тесты. То же самое касается модульных тестов и интеграционных тестов. Если юнит-тест не пройден, он будет каскадным и приведет к всевозможным беспорядкам в интеграционных тестах. Все знают, что когда тесты Unit & Integration не пройдены, вы начинаете с проверки Unittests ...

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

JDT
источник
5

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

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

Вы можете переместить утилиты в их собственное решение и добавить ссылку на их получившуюся DLL в вашем текущем проекте.

Thorsal
источник
4

В итоге вы не хотите использовать инструменты / методы для выполнения действий, отличных от того, для чего они предназначены.

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

Таким образом, вы можете сохранить свои тесты в соответствии с рекомендациями и позволить CI позаботиться о проверке ваших тестов.

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

AvetisG
источник
4

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

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

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

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

Я не знаю, как это работает в Visual Studio, потому что я еще ничего не делал, включая обширное тестирование с C #, но в мире Java это работает следующим образом: в папке с исходным кодом проекта у нас обычно есть две подпапки, один с именем «main», содержащий производственный код, и один с именем «test», содержащий код тестирования. В разделе «main» мы имеем иерархию папок, которая точно соответствует иерархии пакетов нашего исходного кода. Пакеты Java примерно соответствуют пространствам имен C #. В C # не требуется сопоставлять иерархию папок с иерархией пространства имен, но это целесообразно сделать.

Теперь, что люди обычно делают в мире Java, так это то, что в папке «test» они отражают иерархию папок в «основной» папке, так что каждый тест находится в том же пакете, что и класс, который он тестирует. Это объясняется тем, что довольно часто классу тестирования требуется доступ к закрытым для пакета членам тестируемого класса, поэтому класс тестирования должен находиться в том же пакете, что и тестируемый класс. В мире C # не существует такой вещи, как локальная видимость пространства имен, поэтому нет причин отражать иерархию папок, но я думаю, что программисты C # более или менее придерживаются той же дисциплины при структурировании своих папок.

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

Поэтому я называю папки (то есть пакеты) моих тестов следующим образом:

t001_SomeSubsystem
t002_SomeOtherSubsystem
t003_AndYetAnotherSubsystem
...

Это гарантирует, что все тесты для «SomeSubsystem» будут выполнены перед всеми тестами для «SomeOtherSubsystem», которые, в свою очередь, будут выполнены перед всеми тестами для «AndYetAnotherSubsystem», и так далее, и так далее.

Внутри папки отдельные тестовые файлы имеют следующие имена:

T001_ThisTest.java
T002_ThatTest.java
T003_TheOtherTest.java

Конечно, очень помогает, что современные IDE имеют мощные возможности рефакторинга, которые позволяют вам переименовывать целые пакеты (и все подпакеты, и весь код, который на них ссылается) всего за пару кликов и нажатий клавиш.

Майк Накис
источник
2
I don't know about everyone else, but I would prefer to have the freedom to try to do something in an odd way, and see for myself whether the results are better or worse++ приятель. Я не знаю, что мне нравится решение, но мне нравится отношение, которое вы там продемонстрировали.
RubberDuck