Как проверить ожидаемое поведение этого метода в Java: он порождает поток и генерирует исключение при определенных условиях - PullRequest
2 голосов
/ 12 сентября 2010

Предположим, у меня есть метод, который порождает новый поток и выполняет некоторую работу.При определенных условиях вновь созданный поток порождает исключение определенного типа, которое завершает весь процесс.Я хотел бы написать тесты JUnit, чтобы проверить это поведение.Есть ли способ сделать это?

Метод:

private void foo() {
  new Thread() {
    @Override void run() {
      throw new CertainException("exception messages");
    }
  }.start();
}

В тесте (концептуально):

public testExceptionThrownFromNewThread() throws Exception {
  try {
    foo();
    Thread.sleep(5000);  // wait for the exception to be thrown
    fail();
  } catch (CertainException e) {
    assertEquals(e.message, "exception messages");
  }
}

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

Ответы [ 4 ]

4 голосов
/ 12 сентября 2010

Если вы хотите протестировать только код внутри метода run (), выполните рефакторинг его или метода foo () (возможно, в Runnable) и протестируйте его отдельно без запуска из потока.

private void foo() {
    new Thread(new MyRunnable()).start();
}

public class MyRunnable implements Runnable {
    public void run() {
    ....
    }
}

Теперь вы можете создавать экземпляр объекта MyRunnable и вызывать метод run () из вашего теста без необходимости запуска потока.

EDIT

Тестирование создания потока может быть выполнено с помощью ThreadFactory Mock. (как указал Джон Скит).

2 голосов
/ 12 сентября 2010

Вы можете перезаписать значение по умолчанию UncaughtExceptionHandler для потоков. Он вызывается всякий раз, когда поток генерирует исключение. В этом обработчике вы можете проверить, равно ли ожидаемое исключение выданному исключению и, например, проверить сообщения или сосчитать случаи исключения. Используя CountDownLatch, вы также можете проверить, генерируются ли исключения вовремя и сколько из них вы ожидаете.

Это работает, даже если у вас нет доступа к Thread, созданному тестируемым классом. Если у вас есть доступ к нему, конечно, есть более простой подход, например, рефакторинг тестируемого класса и введение прослушивателя исключений или тому подобного. Сделайте тестируемый класс лучше, а также улучшите дизайн, например, удалив зависимость от Threads и непосредственно протестировав тело метода run (), который вы могли бы вывести за пределы.

public class ThreadExceptionTest {

private void foo() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            throw new RuntimeException("exception messages");
        }
    }).start();
}

@Test
public void testFoo() throws Exception {
    final CountDownLatch latch = new CountDownLatch(1);
    final RuntimeException expectedException = new RuntimeException("exception messages");
    UncaughtExceptionHandler eh = new UncaughtExceptionHandler() {

        @Override
        public void uncaughtException(Thread t, Throwable e) {
            if (e.getMessage().equals(expectedException.getMessage()))
                latch.countDown();
        }
    };
    Thread.setDefaultUncaughtExceptionHandler(eh);
    foo();
    assertTrue(latch.await(100,TimeUnit.MILLISECONDS));
}

}

1 голос
/ 12 сентября 2010

Что ж, модульные тесты должны проверять результаты вызовов методов, а не детали реализации.

Если в вашей библиотеке завершается поток, как это влияет на пользователя библиотеки?Может быть, вычисления не будут закончены и конечные результаты не будут записаны в базу данных?Затем проверьте базу данных.Может быть, поток перестанет делать некоторые периодические задачи (например, очистка)?Затем проверьте, выполняется ли очистка.

И если созданное исключение никак не повлияет на пользователя, проверить нечего.Потому что, выбрасывается ли исключение или нет, это просто детали реализации (пользователь никогда не увидит его).

0 голосов
/ 12 сентября 2010

Один из вариантов - сделать возможность запуска потока зависимостью, которую можно указать с помощью существующего интерфейса ThreadFactory.Затем в своем модульном тесте вы можете предоставить специалиста ThreadFactory, который обернет данные Runnable для записи исключений и т. Д.

Вы сможете проверить, что:

  • Использовано ThreadFactory
  • Поток запущен
  • Операция вызвала исключение
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...