Плагин maven-surefire-plugin поддерживает его не поддерживает параллелизм, по крайней мере, не поддерживает изолированный способ CircleCI (отдельные узлы для каждого выполнения теста).
Однако вы можете вручную включить параллелизм в стиле CircleCI двумя способами:
- Используйте сценарий оболочки, чтобы выбрать тесты для запуска на каждом узле, а затем используйте параметр
-Dtest
.
- Пользовательский JUnit 4
TestRule
Сценарий оболочки
Создайте каталог bin
в своем проекте, если у вас его еще нет.
В bin
создайте сценарий оболочки в своем проекте с именем test.sh
со следующим содержимым
#!/bin/bash
NODE_TOTAL=${CIRCLE_NODE_TOTAL:-1}
NODE_INDEX=${CIRCLE_NODE_INDEX:-0}
i=0
tests=()
for file in $(find ./src/test/java -name "*Test.java" | sort)
do
if [ $(($i % ${NODE_TOTAL})) -eq ${NODE_INDEX} ]
then
test=`basename $file | sed -e "s/.java//"`
tests+="${test},"
fi
((i++))
done
mvn -Dtest=${tests} test
Этот скрипт будет искать в вашем каталоге src/test/java
все файлы, оканчивающиеся на Test.java
, и добавлять их в параметр -Dtest
в виде списка, разделенного запятыми, а затем вызывать maven.
Чтобы включить новый тестовый сценарий, поместите в файл circle.yml
следующее:
test:
override:
- ./bin/test.sh:
parallel: true
Что следует отметить:
- Вам может потребоваться настроить этот скрипт, если ваши имена файлов не соответствуют этому соглашению об именовании, ваши файлы расположены в другом месте или вам нужно запустить другую фазу жизненного цикла.
- Если у вас очень много тестов, вы можете обнаружить, что ваш параметр
-Dtest
превышает максимальную длину командной строки Linux.
Junit4 TestRule
Вы можете использовать настраиваемое TestRule, чтобы сделать что-то похожее на приведенное выше в коде Java. Преимущество этого заключается в меньшей индивидуальной конфигурации CircleCI, но налагает некоторые предположения о CircleCI в вашей среде Java.
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.junit.Assume;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
@Slf4j
final class CircleCiParallelRule implements TestRule {
@Override
public Statement apply(Statement statement, Description description) {
boolean runTest = true;
final String tName = description.getClassName() + "#" + description.getMethodName();
final String numNodes = System.getenv("CIRCLE_NODE_TOTAL");
final String curNode = System.getenv("CIRCLE_NODE_INDEX");
if (StringUtils.isBlank(numNodes) || StringUtils.isBlank(curNode)) {
log.trace("Running locally, so skipping");
} else {
final int hashCode = Math.abs(tName.hashCode());
int nodeToRunOn = hashCode % Integer.parseInt(numNodes);
final int curNodeInt = Integer.parseInt(curNode);
runTest = nodeToRunOn == curNodeInt;
log.trace("currentNode: " + curNodeInt + ", targetNode: " + nodeToRunOn + ", runTest: " + runTest);
if (!runTest) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
Assume.assumeTrue("Skipping test, currentNode: " + curNode + ", targetNode: " + nodeToRunOn, false);
}
};
}
}
return statement;
}
}
(Обратите внимание, что я использую Project Lombok (создание журнала) и Apache Commons-Lang (для StringUtils) в приведенном выше коде, но при необходимости их можно легко удалить.
Чтобы включить это, в своем тестовом базовом классе вы можете сделать это, чтобы сбалансировать тест за тестом:
// This will load-balance across multiple CircleCI nodes
@Rule public CircleCiParallelRule className = new CircleCiParallelRule();
Или, если вы хотите сбалансировать класс за классом, вы можете сделать это:
// This will load-balance across multiple CircleCI nodes
@ClassRule public CircleCiParallelRule className = new CircleCiParallelRule();
person
JBCP
schedule
24.09.2014