线程中的 junit 断言引发异常

2022-09-01 12:38:37

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

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

堆栈跟踪

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$3.run(ShardedCounterTest.java:77)

答案 1

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

编辑:

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

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

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


答案 2

Eyal Schneider的答案有一个小小的改进:
ExecutorService允许提交一个,任何抛出的异常或错误都会被返回的重新抛出。
因此,测试可以写成:CallableFuture

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

推荐