Java 线程中的junit断言抛出异常

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2596493/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 09:40:31  来源:igfitidea点击:

junit assert in thread throws exception

javajunitassert

提问by antony.trupe

What am I doing wrong that an exception is thrown instead of showing a failure, or should I not have assertions inside threads?

我做错了什么,抛出异常而不是显示失败,或者我不应该在线程内有断言?

 @Test
 public void testComplex() throws InterruptedException {
  int loops = 10;
  for (int i = 0; i < loops; i++) {
   final int j = i;
   new Thread() {
    @Override
    public void run() {
     ApiProxy.setEnvironmentForCurrentThread(env);//ignore this
     new CounterFactory().getCounter("test").increment();//ignore this too
     int count2 = new CounterFactory().getCounter("test").getCount();//ignore
     assertEquals(j, count2);//here be exceptions thrown. this is line 75
    }
   }.start();
  }
  Thread.sleep(5 * 1000);
  assertEquals(loops, new CounterFactory().getCounter("test").getCount());
}

StackTrace

堆栈跟踪

Exception in thread "Thread-26" junit.framework.AssertionFailedError: expected:<5> but was:<6>
    at junit.framework.Assert.fail(Assert.java:47)
    at junit.framework.Assert.failNotEquals(Assert.java:277)
    at junit.framework.Assert.assertEquals(Assert.java:64)
    at junit.framework.Assert.assertEquals(Assert.java:195)
    at junit.framework.Assert.assertEquals(Assert.java:201)
    at com.bitdual.server.dao.ShardedCounterTest.run(ShardedCounterTest.java:77)

采纳答案by Eyal Schneider

The JUnit framework captures only assertion errors in the main thread running the test. It is not aware of exceptions from within new spawn threads. In order to do it right, you should communicate the thread's termination state to the main thread. You should synchronize the threads correctly, and use some kind of shared variable to indicate the nested thread's outcome.

JUnit 框架仅捕获运行测试的主线程中的断言错误。它不知道新生成线程中的异常。为了正确地做到这一点,您应该将线程的终止状态传达给主线程。您应该正确同步线程,并使用某种共享变量来指示嵌套线程的结果。

EDIT:

编辑:

Here is a generic solution that can help:

这是一个可以提供帮助的通用解决方案:

class AsynchTester{
    private Thread thread;
    private AssertionError exc; 

    public AsynchTester(final Runnable runnable){
        thread = new Thread(new Runnable(){
            public void run(){
                try{            
                    runnable.run();
                }catch(AssertionError e){
                    exc = e;
                }
            }
        });
    }

    public void start(){
        thread.start();
    }

    public void test() throws InterruptedException{
        thread.join();
        if (exc != null)
            throw exc;
    }
}

You should pass it the runnable in the constructor, and then you simply call start() to activate, and test() to validate. The test method will wait if necessary, and will throw the assertion error in the main thread's context.

您应该在构造函数中将 runnable 传递给它,然后您只需调用 start() 来激活,并调用 test() 来验证。如有必要,测试方法将等待,并将在主线程的上下文中抛出断言错误。

回答by Jonathan

Where multiple worker threads are concerned, such as in the original question, simply joining one of them is not sufficient. Ideally, you'll want to wait for all worker threads to complete while still reporting assertion failures back to the main thread, such as in Eyal's answer.

在涉及多个工作线程的情况下,例如在原始问题中,仅仅加入其中一个是不够的。理想情况下,您希望等待所有工作线程完成,同时仍将断言失败报告回主线程,例如在 Eyal 的回答中。

Here's a simple example of how to do this using ConcurrentUnit:

这是一个如何使用ConcurrentUnit执行此操作的简单示例:

public class MyTest extends ConcurrentTestCase {
    @Test
    public void testComplex() throws Throwable {
        int loops = 10;
        for (int i = 0; i < loops; i++) {
            new Thread(new Runnable() {
                public void run() {
                    threadAssertEquals(1, 1);
                    resume();
                }
            }).start();
        }

        threadWait(100, loops); // Wait for 10 resume calls
    }
}

回答by Snicolas

I ended up using this pattern it work with both Runnables and Threads. It is largely inspired from the answer of @Eyal Schneider:

我最终使用了这种模式,它适用于 Runnables 和 Threads。它的灵感主要来自@Eyal Schneider 的回答:

private final class ThreadUnderTestWrapper extends ThreadUnderTest {
    private Exception ex;

    @Override
    public void run() {
        try {
            super.run();
        } catch ( Exception ex ) {
            this.ex = ex;
        }
    }

    public Exception getException() throws InterruptedException {
        super.join(); // use runner.join here if you use a runnable. 
        return ex;
    }
}

回答by MyKey_

A small improvement to Eyal Schneider's answer:
The ExecutorServiceallows to submit a Callableand any thrown Exceptions or Errors are rethrown by the returned Future.
Consequently, the test can be written as:

小改进的Eyal施奈德的回答
ExecutorService允许提交Callable任何抛出的异常或错误被退回被重新抛出Future
因此,测试可以写成:

@Test
public void test() throws Exception {
  ExecutorService es = Executors.newSingleThreadExecutor();
  Future<?> future = es.submit(() -> {
    testSomethingThatMightThrowAssertionErrors();
    return null;
  });

  future.get(); // This will rethrow Exceptions and Errors as ExecutionException
}

回答by Riki Gomez

JUnit throws AssertionError that extends of Throwable, it has the same parent of Exception. You can catch the fail assert of the thread, then save in a static field and finally check in the main thread if the other thread has failed some assert.

JUnit 抛出扩展 Throwable 的 AssertionError,它具有相同的 Exception 父级。您可以捕获线程的失败断言,然后保存在静态字段中,最后在主线程中检查其他线程是否失败了某些断言。

First, create the static field

一、创建静态字段

private volatile static Throwable excepcionTE = null;

Second, wrap the asserts in a try/catch and catch AssertionError

其次,将断言包装在 try/catch 中并捕获 AssertionError

        try
    {
      assertTrue("", mensaje.contains("1234"));
    }
    catch (AssertionError e)
    {
      excepcionTE = e;
      throw e;
    }

And finally, check in the main thread that field

最后,在主线程中检查该字段

 if (excepcionTE != null)
{
  excepcionTE.printStackTrace();
  fail("Se ha producido una excepcion en el servidor TE: "
      + excepcionTE.getMessage());
}