Как запустить Gradle-тест, когда все тесты АКТУАЛЬНЫ?


131

У меня настроен сценарий оценки. Когда я выполняю сборку Gradle, все работает и запускает тесты jUnit.

После этого, когда я запускаю тест Gradle, я получаю следующее:

C:\Users\..\..\Project>gradle test
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE

Когда я выполняю gradle clean, сборка Gradle, конечно, работает ... Я хочу иметь возможность сбрасывать только тесты, а не собирать весь проект: как мне это сделать?


3
Это кажется ненужным, исходя из предоставленной информации. Если ни код приложения, ни тестовый код не изменились, зачем вам повторно запускать тесты?
Jolta

10
@Jolta Некоторые тесты в моем коде связаны с сторонними входами, я запускаю свои тесты не только для того, чтобы убедиться, что я не вставил никаких ошибок в код, но и для проверки, если что-то изменилось на сторонних входах что я получаю
USer22999299

4
Извините за придирчивость, но я не думаю, что это правильный способ думать об этом: если у вас есть переменные сторонние входы, это не правильный способ справиться с этим, чтобы каким-то образом издеваться над этими входами? Фактически, тестирование должно быть связано с тестированием кода, который вы пишете. Разве вам не грозит очевидная опасность получения ложных срабатываний, если вы полагаетесь на неприемлемый сторонний ввод? Разве стратегия не должна заключаться в том, чтобы учитывать ввод проблемы как часть кода вашего приложения?
Майк грызун

9
@mikerodent рассмотрите возможность тестирования вашего кода на стороннем онлайн-сервисе. Вы хотели бы отслеживать возможные изменения в сервисном API, чтобы иметь возможность как можно скорее ответить развернутыми исправлениями. Разве тесты CI - не хороший способ сделать это? Использование макета только скажет вам, что ваш собственный код не имеет регрессий, но зависимости все еще могут иметь изменения. использование реальной услуги будет означать, что ваш продукт действительно может выполнять ожидаемые операции в текущей среде.
Elist

5
Это также справедливо с точки зрения интеграционного тестирования, где целью теста является проверка интеграции вашего кода с другими фрагментами кода, где было бы неуместно высмеивать зависимости
1800 ИНФОРМАЦИЯ

Ответы:


172

Один из вариантов - использовать --rerun-tasksфлаг в командной строке . Это приведет к повторному запуску всей тестовой задачи и всех задач, от которых она зависит.

Если вас интересует только повторный запуск тестов, то другой вариант - заставить gradle очищать результаты тестов перед выполнением тестов. Это можно сделать с помощью cleanTestзадания.

Немного предыстории - плагин Java определяет чистые задачи для каждой из других задач. Согласно документации :

cleanTaskName - удаляет файлы, созданные указанной задачей. cleanJar удалит файл JAR, созданный задачей jar, а cleanTest удалит результаты теста, созданные задачей test.

Следовательно, все, что вам нужно для повторного запуска тестов, - это также запустить cleanTestзадачу, то есть:
gradle cleanTest test


3
gradle cleanTest testне перезапускает тесты, он очищает их вывод, но testзадача все равно будет получать результаты теста из кеша - см. github.com/gradle/gradle/issues/9153
dan.m was user2321368

3
Комментарий выше правильный. Но если использовать --no-build-cache, то будет работать как положено, например gradle cleanTest test --no-build-cache.
vRallev

51

Другой вариант - добавить в build.gradle следующее:

test.outputs.upToDateWhen {false}

1
Я использовал эту технику для funcTestзадачи, которую создал для выполнения функциональных тестов.
pharsicle

4
Это гораздо лучший подход, чем принятый ответ, поскольку он будет применяться только к желаемой задаче. upToDateWhenМожет быть использован в любой «кода управляемой» , как например, системные свойства, переменные окружения, свойства проекта и т.д.
mkobit

1
Как упоминается в ответе stackoverflow.com/a/52484259/340175 , есть полезная запись в блоге blog.gradle.org/stop-rerunning-tests, в которой объясняется, почему этот подход не рекомендуется в качестве общего подхода. Тем не менее, я согласен с тем, что это может быть полезно и действительно дает ответ на вопрос.
JulianHarty

Да, это устаревший ответ, когда я писал, этот Gradle был в версии 2.11 и только начал использоваться, но все еще имел много шероховатостей, которые сегодня отполированы.
František Hartman

1
Отличный ответ !!! Сдал его с помощью параметра: gradle test -Prerun-tests. Код в build.gradle:if(project.hasProperty("rerun-tests")) { test.outputs.upToDateWhen {false} }
AlikElzin-kilaka

22

gradle test --rerun-tasks

Указывает, что любая оптимизация задачи игнорируется.

Источник: https://gradle.org/docs/current/userguide/gradle_command_line.html


3
Я думаю, что он также повторно запустит все зависимые задачи, что не является предполагаемым поведением запрашивающего.
AlikElzin-kilaka

17

Это недавно была тема в блоге Gradle. Прекратите повторный запуск тестов . Автор показывает пример использования outputs.upToDateWhen { false }и объясняет , почему это не так:

На самом деле это не приводит к повторному запуску

Вероятно, автор этого фрагмента хотел сказать: «Всегда повторяйте мои тесты». Но это не то, что делает этот фрагмент. Он только пометит задачу как устаревшую, заставив Gradle воссоздать вывод. Но вот в чем дело: если кеш сборки включен, Gradle не нужно запускать задачу для воссоздания вывода. Он найдет запись в кеше и распакует результат в выходной каталог теста.

То же верно и для этого фрагмента:

test.dependsOn cleanTest

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

Если вы сейчас думаете: «Хорошо, я тоже отключу кеш», позвольте мне сказать вам, почему вам не следует этого делать.

Затем автор объясняет, почему повторный запуск некоторых тестов - пустая трата времени:

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

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

task randomizedTest(type: Test) {
  systemProperty "random.testing.seed", new Random().nextInt()
}

task systemIntegrationTest(type: Test) {
  inputs.property "integration.date", LocalDate.now()
}

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


8
Это звучит отлично для конкретного случая использования, о котором вы говорите, но я пишу тесты после развертывания для действующей внешней веб-службы и просто использую для этого junit и gradle. Код испытуемый не живет в репо, а на самом деле там нет никакого «кода приложения» , потому что я на самом деле тестирование живой системы производства , а не сам код. Спасибо за ответ, очень полезно! Просто хотел указать, что есть дополнительные варианты использования, которые требуют повторного запуска тестов каждый раз, даже если ни один из кодов, о которых gradle не знает, не меняется
Брэндон

11

Вот решение, использующее файл "build.gradle" на случай, если вы не хотите изменять свою командную строку:

test {
    dependsOn 'cleanTest'
    //Your previous task details (if any)
}

И вот результат. Обратите внимание на 2 изменения по сравнению с предыдущим выводом:

1) На выходе появляется новая задача cleanTest.

2) 'test' всегда очищается (т.е. никогда не 'UP-TO-DATE'), поэтому он выполняется каждый раз:

$ gradle build
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:findMainClass
:jar
:bootRepackage
:assemble
:cleanTest
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test
:check
:build

1
предыдущий запуск cleanTestне testбудет повторно запускать тесты, он очищает их выходные данные, но тестовая задача по-прежнему будет получать результаты теста из кеша - см. github.com/gradle/gradle/issues/9153
dan.m was user2321368

8

--rerun-tasks работает, но неэффективно, поскольку повторно выполняет все задачи.

cleanTest сам по себе может не хватить из-за кеша сборки.

Итак, лучший способ добиться этого:

./gradlew --no-build-cache cleanTest test

0

Кроме того, необходимость добавления --rerun-tasksдействительно избыточна. Никогда не бывает. Создать --no-rerun-tasksи использовать по --rerun-tasksумолчанию, когдаcleanTask


-1

TL; DR

test.dependsOn cleanTest

2
Согласно stackoverflow.com/a/52484259/466862 , это не сработает.
Марк Роттевил

Ну, документация gradle немного сбивает с толку .... Здесь говорят, что для этой цели можно использовать cleanTest. docs.gradle.org/current/userguide/… . Кроме того, он работает на моей машине (и версии Gradle 4.10.3);)
Topera

-4

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

Но я бы поставил под сомнение необходимость когда-либо делать это, как сказал Джолта в своем комментарии: если код не изменился, зачем вам повторное тестирование? Если у вас есть сомнения относительно стороннего ввода, я бы сказал, что вам нужно учесть это в своем коде приложения. Если вас беспокоит, что ваш код может быть "нестабильным", т.е. может пройти все тесты с первого раза, но не во второй (или сотый), разве вам не нужно думать о том, почему у вас есть эти сомнения, и устранять их?

Лично я считаю, что это (очень незначительная) ошибка дизайна в Gradle: если все полностью обновлено, вместо того, чтобы идти «СОЗДАТЬ УСПЕШНО», должно быть сказано «БЕЗ ИЗМЕНЕНИЙ С ПОСЛЕ ПОСЛЕДНЕЙ УСПЕШНОЙ СБОРКИ: НИЧЕГО НЕ СДЕЛАНО».


3
«Разве вам не нужно думать о том, почему у вас возникают эти сомнения, и решать их?»: Да, но чтобы получить данные для размышлений, я хотел бы запустить тесты несколько раз и посмотреть, что произойдет. Это так безумие?
mhsmith

1
@mikerodent Я частично согласен с вашей точкой зрения. Существуют «легкие» случаи, как правило, простые модульные тесты белого ящика, когда отсутствие изменения кода означает, что на самом деле нечего повторно тестировать. Однако подумайте о тестах с зависимостями. «О да, докер не работал и т. Д.» Существуют тесты, в которых именно инфраструктура (а в dev вы) устанавливает зависимости (они «предоставляются»), а не сборка. В этих случаях я всегда хочу иметь возможность повторно запустить.
dbalakirev

@dbalakirev Да, это пришло мне в голову ... но разве вы не должны высмеивать роль этих зависимостей, например Docker ...? Я имею в виду, если вы этого не делаете, разве вы не накапливаете будущие проблемы? Я не говорю, что уверен на 100%, но я думаю, что я говорю, что ваши тесты должны, в мире, без сомнения, более идеальном, чем наш, охватывать все базы.
Майк грызун

Вы можете издеваться над «да», с которым у вас есть зависимость (докер), что если у вас что-то не получается, это означает, что вы хотите перезапустить, даже если код не изменился. Я хотел бы подчеркнуть, что эта мысль не относится к модульным тестам или тестам, где 1. вы пытаетесь избежать зависимостей 2. или, по крайней мере, имитируете их с помощью тестовой среды, а когда они действительно «предоставляются», если хотите.
dbalakirev

2
__ если код не изменился, зачем вам повторное тестирование? __ Слышали ли вы об интеграционных тестах?
Bogdan Mart
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.