Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JUnit tearDown()在我的测试完成之前完成执行(使用自定义运行程序)_Java_Multithreading_Junit_Jira Rest Java Api - Fatal编程技术网

Java JUnit tearDown()在我的测试完成之前完成执行(使用自定义运行程序)

Java JUnit tearDown()在我的测试完成之前完成执行(使用自定义运行程序),java,multithreading,junit,jira-rest-java-api,Java,Multithreading,Junit,Jira Rest Java Api,JUnit@AfterClass方法在my@Tests(自定义运行程序)之前完成执行 我正在尝试制作我自己的JUnit测试运行程序。每次执行@AfterClass注释的方法时,我都想做一些事情。根据JUnit文档,@AfterClass方法应该在所有测试运行之后开始执行 我浏览了google,彻底使用了JUnit文档,阅读了 StackOverflow上的JUnit执行顺序等,但我似乎找不到任何其他发生这种情况的例子(可能是线程问题)。我发现了一个Spring使用自己的runner的例子,但它并

JUnit@AfterClass方法在my@Tests(自定义运行程序)之前完成执行

我正在尝试制作我自己的JUnit测试运行程序。每次执行@AfterClass注释的方法时,我都想做一些事情。根据JUnit文档,@AfterClass方法应该在所有测试运行之后开始执行

我浏览了google,彻底使用了JUnit文档,阅读了 StackOverflow上的JUnit执行顺序等,但我似乎找不到任何其他发生这种情况的例子(可能是线程问题)。我发现了一个Spring使用自己的runner的例子,但它并没有帮助我解决这个问题

public class CustomRunner extends BlockJUnit4ClassRunner {

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

    @Override
    protected Statement withAfterClasses(Statement statement) {
        Statement s = super.withAfterClasses(statement);
        System.out.println("tearDown() executed!");
        return s;
    }
}
使用CustomRunner:

public class TestBugReporter0 {

    @Before
    public void setUp() {}

    @Test
    public void testAssertionFailure() {
        assertEquals(3, 2);
    }

    @AfterClass
    public static void tearDown() {
        System.out.println("tearDown() executed!");
    }
}
@RunWith(CustomRunner.class)
public class TestBugReporter1 {

    @Before
    public void setUp() {}

    @Test
    public void testAssertionFailure() {
        assertEquals(3, 2);
    }

    @AfterClass
    public static void tearDown() {}
}
TestBugReporter0始终打印以下内容:

setUp() executed!
java.lang.AssertionError: Expected :3, Actual :2
tearDown() executed!
然而,TestBugReporter1不是确定性的。跑了20次后,我总是得到以下三分之一

tearDown() executed!
setUp() executed!
java.lang.AssertionError: Expected :3, Actual :2

java.lang.AssertionError: Expected :3, Actual :2
tearDown() executed!
setUp() executed!

setUp() executed!
java.lang.AssertionError: Expected :3, Actual :2
tearDown() executed!
我认为这是一个线程问题,因为:

  • 结果是不确定的
  • 这些方法按顺序执行
  • 如果我在CustomRunner中的withAfterClasses()方法中添加Thread.sleep(3000),我总是得到三种可能性中的第一种。我可能会在不同的睡眠中强制执行三种可能性中的任何一种,例如,将一种放置在tearDown()中会强制执行第三种。然而,Thread.sleep()并不是真正的解决方案

    让整个TestBugReporter1方法以正确的顺序决定性地执行吗?如果是的话,我会怎么做?如果你知道一个比把所有东西都放在一个线程上更好的解决方案,请大声说出来!:)

    提前感谢您的帮助,感谢您在没有解释链接含义的情况下不复制粘贴链接。我的多线程背景非常有限,因此如果没有上下文,我可能无法理解文档


    注意:TestNG有一个单线程配置,但我们现有的测试套件是纯JUnit,因此它不是一个选项。

    方法
    和AfterClass
    (以及以
    开头的任何其他方法)不从测试类执行任何操作。相反,它们构建了一个
    语句
    对象链,表示稍后将执行的内容

    语句

    表示在执行过程中运行时要执行的一个或多个操作 运行JUnit测试套件

    请看一看类
    runafter
    ,它是
    语句
    的一个子类,由
    与afterclasses的默认实现返回

    JUnit似乎可以在测试类生命周期的不同时间请求此
    语句
    ;但是,您不应该关心这一点-只需返回一个实例
    语句
    。您可以将其视为命令模式

    更新

    标准的
    runafter
    实现使得在调用
    @AfterClass
    之前或在
    @AfterClass
    方法之后很难进行子类化和操作,因此我前面的建议不容易实现

    这是你可以做到的

    CustomRunner:

    public class TestBugReporter0 {
    
        @Before
        public void setUp() {}
    
        @Test
        public void testAssertionFailure() {
            assertEquals(3, 2);
        }
    
        @AfterClass
        public static void tearDown() {
            System.out.println("tearDown() executed!");
        }
    }
    
    @RunWith(CustomRunner.class)
    public class TestBugReporter1 {
    
        @Before
        public void setUp() {}
    
        @Test
        public void testAssertionFailure() {
            assertEquals(3, 2);
        }
    
        @AfterClass
        public static void tearDown() {}
    }
    
    公共类CustomRunner扩展了BlockJUnit4ClassRunner{
    公共CustomRunner(类klass)引发初始化错误{
    超级(klass);;
    }
    @凌驾
    带AfterClass的受保护语句(语句语句){
    List after=getTestClass().getAnnotatedMethods(AfterClass.class);
    语句=新CustomRunAfter(语句,After,null);
    返回语句;
    }
    }
    
    自定义RunAfter:

    公共类CustomRunAfter扩展语句{
    非公开最终报表fNext;
    私有最终目标;
    私人最终名单;
    公共CustomRunAfter(下一个语句、列表After、对象目标){
    fNext=下一个;
    fAfters=after;
    fTarget=目标;
    }
    @凌驾
    public void evaluate()可丢弃{
    List fErrors=新的ArrayList();
    弗罗尔斯。克利尔();
    试一试{
    fNext.evaluate();
    }捕获(可丢弃的e){
    添加(e);
    }最后{
    beforetrunafter();
    对于(每个框架方法:fAfters){
    试一试{
    each.invokeeexplosive(fTarget);
    }捕获(可丢弃的e){
    添加(e);
    }
    }
    afterrunafter();
    }
    if(fErrors.isEmpty())
    返回;
    如果(fErrors.size()==1)
    抛出fErrors.get(0);
    抛出新的MultipleFailureException(fErrors);
    }
    私有无效后运行(){
    System.err.println(“在运行@AfterClass方法之后”);
    }
    运行之前的私有无效(){
    System.err.println(“在运行@AfterClass方法之前”);
    }
    }
    
    在上面的代码中,您可以在
    beforeRunAfter
    afterRunAfter
    方法中执行自定义操作


    注意:上面的代码片段包含JUnit4.5中修改过的源代码。在必要的情况下,我在此使用与JUnit(Eclipse公共许可证)等相同的许可证对我的修改进行许可。

    处理顺序正确

    问题是输出。 输出将写入System.out,而断言错误将使用System.err打印

    它们的输出顺序不一定正确

    另见


    我认为这不是本例中的问题,因为输出不是确定性的。为什么不试试?JUnit可以在它喜欢的任何时间点用AfterClass调用
    ,因为它实际上并没有执行任何代码;相反,它是建立一个声明性的动作链,稍后再执行。是的,你是对的。但是,代码片段并不一致。TestBugReporter0类包含@AfterMethod中的输出以及CustomRunner中的方法