代码之家  ›  专栏  ›  技术社区  ›  antony.trupe

JUnit断言在线程中引发异常

  •  19
  • antony.trupe  · 技术社区  · 16 年前

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

     @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)
    
    5 回复  |  直到 7 年前
        1
  •  32
  •   Eyal Schneider    8 年前

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

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

        2
  •  5
  •   Community Mohan Dere    9 年前

    对…的小小改进 Eyal Schneider's answer :
    这个 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
    }
    
        3
  •  4
  •   Jonathan    15 年前

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

    下面是一个使用 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
        }
    }
    
        4
  •  0
  •   Snicolas    13 年前

    我最终使用了这个模式,它可以同时处理runnable和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;
        }
    }
    
        5
  •  0
  •   Riki Gomez    7 年前

    junit抛出扩展了throwable的assertionerror,它有相同的exception父级。您可以捕获线程的fail断言,然后保存在一个静态字段中,如果另一个线程的某些断言失败,则最后签入主线程。

    首先,创建静态字段

    private volatile static Throwable excepcionTE = null;
    

    其次,将断言包装在try/catch-and-catch断言错误中

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

    最后,签入该字段的主线程

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