线程中的junitAssert抛出异常

vwoqyblh  于 2022-11-11  发布在  其他
关注(0)|答案(5)|浏览(168)

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

@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)
myss37ts

myss37ts1#

JUnit框架只捕获运行测试的主线程中的Assert错误。它不知道来自新衍生线程中的异常。为了正确地执行它,您应该将线程的终止状态通知给主线程。您应该正确地同步线程,并使用某种共享变量来指示嵌套线程的结果。
编辑:
下面是一个通用的解决方案,可以帮助:

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()来验证。如果需要的话,test方法将等待,并在主线程的上下文中抛出Assert错误。

cotxawn7

cotxawn72#

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

tktrz96b3#

在涉及多个工作线程的情况下,例如在最初的问题中,仅仅加入其中一个是不够的。理想情况下,您将希望等待所有工作线程完成,同时仍然向主线程报告Assert失败,如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
    }
}
zaqlnxep

zaqlnxep4#

我最终使用了这个模式,它可以同时处理Runnables和Threads。它的灵感主要来自于@ EyalSchneider的回答:

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

pprl5pva5#

JUnit抛出的AssertionError是Throwable的扩展,它与Exception具有相同的父级。您可以捕获线程的失败Assert,然后将其保存在静态字段中,最后在主线程中检查是否其他线程的某个Assert失败。
首先,创建静态字段

private volatile static Throwable excepcionTE = null;

其次,将Assert Package 在try/catch中,并捕获AssertionError

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

相关问题