junit assert в потоке выдает исключение - PullRequest
19 голосов
/ 08 апреля 2010

Что я делаю не так, что возникает исключение вместо того, чтобы показывать ошибку, или у меня не должно быть утверждений внутри потоков?

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

Ответы [ 5 ]

33 голосов
/ 08 апреля 2010

Среда JUnit фиксирует только ошибки утверждений в основном потоке, выполняющем тест. Он не знает об исключениях из новых потоков порождения. Чтобы сделать это правильно, вы должны сообщить о состоянии завершения потока в основной поток. Вы должны правильно синхронизировать потоки и использовать какую-то общую переменную, чтобы указать результат вложенного потока.

EDIT:

Вот общее решение, которое может помочь:

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 () для проверки. При необходимости тестовый метод будет ждать и выдаст ошибку подтверждения в контексте основного потока.

5 голосов
/ 15 ноября 2016

Небольшое улучшение до Ответ Эяля Шнайдера :
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
}
4 голосов
/ 25 октября 2010

Если речь идет о нескольких рабочих потоках, например, в первоначальном вопросе, простого присоединения к одному из них недостаточно. В идеале вам следует дождаться завершения всех рабочих потоков, в то же время сообщая об ошибках подтверждения обратно в основной поток, например в ответе Эяля.

Вот простой пример того, как сделать это, используя 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
    }
}
0 голосов
/ 11 января 2019

JUnit генерирует AssertionError, которая распространяется на Throwable, у него тот же родительский объект Exception. Вы можете перехватить утверждение потока в потоке, затем сохранить его в статическом поле и, наконец, проверить в основном потоке, если другой поток провалил какое-либо утверждение.

Сначала создайте статическое поле

private volatile static Throwable excepcionTE = null;

Во-вторых, заверните утверждения в попытке / поймать и поймать 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());
}
0 голосов
/ 05 декабря 2012

В итоге я использовал этот шаблон, он работает как с 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;
    }
}
...