在没有显式测试套件类声明的所有JUnit测试之后进行清理

时间:2016-05-27 00:06:51

标签: java eclipse unit-testing junit code-cleanup

在Intelij和Eclipse IDE(也可能是其他一些IDE)中,可以从包(甚至是项目中的所有测试类)运行所有测试类,而无需将每个测试类显式地放在测试套件类中( this是我想要避免的事情)。只需右键单击 - >运行所有测试并vo!

我对这种测试方法有一个问题。我想在完成所有测试后做一些清理工作,但无论我做什么,似乎没什么用。

首先,我尝试使用RunListener及其testRunFinished()方法,但是在每次原子测试完成后都会调用它,所以在运行其中很多时都不是我想要的。

然后我想到了终结器和runFinalizersOnExit(true),不幸的是,它被弃用了,只在一台执行测试的计算机上工作。

我尝试的最后一件事是创建一个“监听器”线程,例如,测试执行开始和结束时间差异 - 将在测试完成五秒后清理。我使用下面的代码来测试该解决方案:

import org.junit.Test;

public class Main {
    static {
        System.out.println("In a static block!");

        new Thread(new Runnable() {
            public void run() {
                System.out.println("Starting static thread!");

                try {
                    while (true) {
                        Thread.sleep(1000);
                        System.out.println("Static thread working...");
                    }
                } catch (InterruptedException e) {
                    System.err.println("Static thread interrupted!");
                    e.printStackTrace();
                } catch (Exception e) {
                    System.err.println("Static thread catches exception!");
                    e.printStackTrace();
                } finally {
                    System.err.println("Static thread in finally method.");
                    Thread.currentThread().interrupt();
                }

            }
        }).start();

        System.out.println("Exiting static block!");
    }

    @Test
    public void test() throws Exception {
        System.out.println("Running test!");
        Thread.sleep(3000);
        System.out.println("Stopping test!");
    }
}

没有运气。测试完成后线程被杀死。甚至finally块也永远不会被执行......

In a static block!
Exiting static block!
Running test!
Starting static thread!
Static thread working...
Static thread working...
Stopping test!
Static thread working...

期望的行为是:

  1. 右键单击
  2. 运行所有测试
  3. TestA正在运行......
  4. TestA已完成
  5. TestB正在运行......
  6. TestB已完成
  7. ...更多测试类......
  8. 清理

2 个答案:

答案 0 :(得分:1)

不确定我的问题是否完全正确,但我认为您之前,之前,之后和之后的类方法都需要。即。

@BeforeClass
public void beforeClass() {
    // Do stuff before test class is run
}

@Before
public void before() {
    // Do stuff before each test is run
}

@After
public void after() {
    // DO stuff after each test is run
}

@AfterClass
public void afterClass() {
    // DO stuff after test class is run
}

你可以通过一些黑客或其他框架在更全球的层面上做事。例如,Spring的测试套件。但我会尝试将这些内容保留在单个测试类的范围内。

答案 1 :(得分:1)

我找到了解决问题的方法。我的同事建议“嘿,难道你不能算上考试班吗?” - 这就是我所做的。

这里使用了一点反射魔法,因此代码可能不可移植:

public abstract class CleaningTestRunner extends BlockJUnit4ClassRunner {
    protected abstract void cleanupAfterAllTestRuns();

    private static long TEST_CLASSES_AMOUNT;
    private static long TEST_RUNS_FINISHED = 0;
    private static boolean CLASSES_COUNTED = false;

    static {
        while (!CLASSES_COUNTED) {
            try {
                Field f = ClassLoader.class.getDeclaredField("classes");
                f.setAccessible(true);

                Vector<Class> classes = (Vector<Class>) f.get(CleaningTestRunner.class.getClassLoader());
                TEST_CLASSES_AMOUNT = 0;
                for (Class<?> klass : classes) {
                    if (klass.isAnnotationPresent(RunWith.class)) {
                        if (CleaningTestRunner.class.isAssignableFrom(klass.getAnnotation(RunWith.class).value())) {
                            for (Method method : klass.getMethods()) {
                                if (method.isAnnotationPresent(Test.class)) {
                                    ++TEST_CLASSES_AMOUNT;
                                    break;
                                }
                            }
                        }
                    }

                }

                CLASSES_COUNTED = true;
            } catch (Exception ignored) {

            }
        }
    }

    public CleaningTestRunner(Class<?> klass) throws InitializationError {
        super(klass);
    }

    @Override
    public void run(RunNotifier notifier) {
        notifier.addListener(new TestCleanupListener());
        super.run(notifier);
    }

    private class TestCleanupListener extends RunListener {
        @Override
        public void testRunFinished(Result result) throws Exception {
            ++TEST_RUNS_FINISHED;

            if (TEST_RUNS_FINISHED == TEST_CLASSES_AMOUNT) {
                cleanupAfterAllTestRuns();
            }
        }
    }
}