1

我有一个自定义测试运行器来运行我的部分测试,因此我可以将测试分布在不同的詹金斯节点上。如果我所有的集成测试都运行了,那将需要一个小时。所以我有 3 台服务器运行 1/3 的测试,总共只需要 20 分钟。这是我的套房的外观:

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;
    }
}

这种工作,除非我尝试在不同的模块中使用多个 DistibutedIntegrationTestRunners 并一次运行它们,“事情不起作用”。通常我不会在 SO 上发布含糊不清的投诉,但很难弄清楚更多,因为这段代码没有给出太多反馈。这是我得到的唯一日志:

        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());

这发生在任何测试运行之前。如果我可以获得比这更多的日志记录,那将非常有用。例如,如果我可以在测试运行之前打印出“我即将运行 FooTest”,那将非常有用。有没有办法做到这一点?

我浏览了源代码,发现 中有一个名为 的字段private final RunNotifier fNotifier;org.junit.internal.runners.JUnit38ClassRunner但我不确定如何使用它,或者我是否会朝着正确的方向前进。

我使用的是 JUnit 4.10,但如有必要,我可以升级。

4

1 回答 1

0

这对我来说似乎是一个 XY 问题。

日志文件不用于测试。它们用于监视调试。一旦你有一个失败的测试用例,你需要从考虑测试转向考虑调试。这意味着单独运行失败的测试用例,可能使用调试器。

如果您的测试失败并显示无用的失败消息,则表明您的低级测试覆盖率很差,或者来自测试用例的诊断消息很差。

于 2014-04-24T11:52:50.380 回答