现在我们有一个项目可以建立两个工作岗位。 1)标准构建是否具有单元测试。 2)是集成测试。他们的工作方式如下:
问题是步骤2)现在需要花费一个多小时来运行,我想并行化集成测试,以便花费更少的时间。但我不确定我该怎么做/应该这样做。我的第一个想法是,我可以有两个这样的步骤:
但是,如何在集成服务器1上运行一半集成测试,另一半在集成服务器2上运行?我正在使用maven,所以我可能会找出failsafe和复杂包含/排除模式的东西。但这听起来像需要付出很多努力来维持。 EG:当有人添加新的集成测试类时,如何确保它在两个服务器之一上运行?开发人员是否必须修改maven模式?
答案 0 :(得分:2)
我发现this great article有关如何执行此操作,但它提供了一种在Groovy代码中执行此操作的方法。我几乎遵循了这些步骤,但我没有编写代码来按持续时间均匀地分配测试。但这仍然是一个有用的工具,所以我会分享它。
import junit.framework.JUnit4TestAdapter;
import junit.framework.TestSuite;
import org.junit.Ignore;
import org.junit.extensions.cpsuite.ClassesFinder;
import org.junit.extensions.cpsuite.ClasspathFinderFactory;
import org.junit.extensions.cpsuite.SuiteType;
import org.junit.runner.RunWith;
import org.junit.runners.AllTests;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@RunWith(AllTests.class)
public class DistributedIntegrationTestRunner {
private static Logger log = LoggerFactory.getLogger(DistributedIntegrationTestRunner.class);
public static TestSuite suite() {
TestSuite suite = new TestSuite();
ClassesFinder classesFinder = new ClasspathFinderFactory().create(true,
new String[]{".*IntegrationTest.*"},
new SuiteType[]{SuiteType.TEST_CLASSES},
new Class[]{Object.class},
new Class[]{},
"java.class.path");
int nodeNumber = systemPropertyInteger("node.number", "0");
int totalNodes = systemPropertyInteger("total.nodes", "1");
List<Class<?>> allTestsSorted = getAllTestsSorted(classesFinder);
allTestsSorted = filterIgnoredTests(allTestsSorted);
List<Class<?>> myTests = getMyTests(allTestsSorted, nodeNumber, totalNodes);
log.info("There are " + allTestsSorted.size() + " tests to choose from and I'm going to run " + myTests.size() + " of them.");
for (Class<?> myTest : myTests) {
log.info("I will run " + myTest.getName());
suite.addTest(new JUnit4TestAdapter(myTest));
}
return suite;
}
private static int systemPropertyInteger(String propertyKey, String defaultValue) {
String slaveNumberString = System.getProperty(propertyKey, defaultValue);
return Integer.parseInt(slaveNumberString);
}
private static List<Class<?>> filterIgnoredTests(List<Class<?>> allTestsSorted) {
ArrayList<Class<?>> filteredTests = new ArrayList<Class<?>>();
for (Class<?> aTest : allTestsSorted) {
if (aTest.getAnnotation(Ignore.class) == null) {
filteredTests.add(aTest);
}
}
return filteredTests;
}
/*
TODO: make this algorithm less naive. Sort each test by run duration as described here: http://blog.tradeshift.com/just-add-servers/
*/
private static List<Class<?>> getAllTestsSorted(ClassesFinder classesFinder) {
List<Class<?>> allTests = classesFinder.find();
Collections.sort(allTests, new Comparator<Class<?>>() {
@Override
public int compare(Class<?> o1, Class<?> o2) {
return o1.getSimpleName().compareTo(o2.getSimpleName());
}
});
return allTests;
}
private static List<Class<?>> getMyTests(List<Class<?>> allTests, int nodeNumber, int totalNodes) {
List<Class<?>> myTests = new ArrayList<Class<?>>();
for (int i = 0; i < allTests.size(); i++) {
Class<?> thisTest = allTests.get(i);
if (i % totalNodes == nodeNumber) {
myTests.add(thisTest);
}
}
return myTests;
}
}
ClasspathFinderFactory
用于查找与.*IntegrationTest
模式匹配的所有测试类。
我创建N个作业并且它们都运行此Runner
但是它们都为node.number
系统属性使用不同的值,因此每个作业运行一组不同的测试。这是故障安全插件的外观:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.12.4</version>
<executions>
<execution>
<id>integration-tests</id>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<includes>
<include>**/DistributedIntegrationTestRunner.java</include>
</includes>
<skipITs>${skipITs}</skipITs>
</configuration>
</plugin>
ClasspathFinderFactory
来自
<dependency>
<groupId>cpsuite</groupId>
<artifactId>cpsuite</artifactId>
<version>1.2.5</version>
<scope>test</scope>
</dependency>
我认为应该有一些Jenkins插件,但我找不到。接近的是Parallel Test Executor,但我不认为这与我需要的东西相同。看起来它在单个作业/服务器而不是多个服务器上运行所有测试。它没有提供一个明显的方式来说,“在这里运行这些测试,并在那里进行那些测试”。
答案 1 :(得分:1)
我相信你现在已经找到了一个解决方案,但是我会给那些打开这个页面的人提出一条道路,问同样的问题:
并行测试执行程序插件:
“这个插件添加了一个新的构建器,可以让您轻松地并行执行在单独作业中定义的测试。这可以通过让Jenkins查看上次运行的测试执行时间,将测试分成大小相等的多个单元,然后执行他们并行。“
https://wiki.jenkins-ci.org/display/JENKINS/Parallel+Test+Executor+Plugin
答案 2 :(得分:0)
是的,Parallel Test Executor是一个很酷的插件,如果你有2个slave或者一个slave有8个执行器,因为这个插件基于&#34;测试分裂&#34;例如:您将junit测试分成4个不同的数组,这些数组将在您指定的该从属服务器上的4个不同执行程序上运行。我希望你得到它:D,它取决于你想要运行并行测试的那个从站上的执行器数量,或者你应该将拆分测试从4减少到2。