【问题标题】:Cleaning up after all JUnit tests without explicit test suite classes declaration在没有明确的测试套件类声明的情况下清理所有 JUnit 测试
【发布时间】:2016-05-27 00:06:50
【问题描述】:

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

不过,我对这种测试方法有一个问题。我想在所有测试完成后进行一些清理,但无论我做什么,似乎都没有任何效果。

起初,我尝试使用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. 测试完成
  5. TestB 正在运行...
  6. TestB 完成
  7. ...更多测试类...
  8. 清理

【问题讨论】:

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


    【解决方案1】:

    不确定我是否完全正确地回答了您的问题,但我认为您需要 before、beforeClass、after 和 afterClass 方法。即

    @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 的测试套件。但我会尽量将这些内容保留在单个测试类的范围内。

    【讨论】:

    • 不,它仍然在执行after single test class,而不是在所有这些都完成之后。我正在多个测试类中运行测试。
    • 好的。然后你需要开始弄乱套件或考虑使用其他可以处理这个问题的框架。但我想知道是否有更好的方法是重构测试,以便在每个测试类之后进行清理。您可能正试图以太大的规模工作。
    • 测试重用了一些需要长时间初始化的静态对象。所述对象仅在测试失败时重新初始化,否则它们处于可预测状态。不过,在删除之前,必须清理一些东西,否则运行测试的人必须手动完成。套件在这里很不方便,因为有很多测试类,而且大多数时候一次只运行少数几个,因为整体执行时间真的很长。
    • 不会运行 - @BeforeClass@AfterClass 要求方法为 static
    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-04
      • 2013-03-30
      • 1970-01-01
      • 1970-01-01
      • 2019-07-22
      • 2023-01-09
      • 1970-01-01
      相关资源
      最近更新 更多