什么是测试Runnables的“正确”方法,JUnit测试无法直接看到它?

时间:2015-06-11 10:37:24

标签: java multithreading unit-testing junit

我要创建一系列测试,其中一些测试导致部分工作在单独的线程中完成。因为这项工作发生在另一个线程中,并且它不接受任何对象作为参数,所以JUnit / Mockito无法看到线程内发生的事情。这意味着如果代码以某种方式失败,那么JUnit就无法看到抛出的异常,这意味着它将假设在测试期间没有抛出任何异常,并且可能在不应该的情况下“传递”它。

有问题的runnable没有直接与启动它的线程通信,所以目前我一直在创建测试,只是寻找线程对其工作的其他文件所做的外部印象,调用数据库,等

这是一种合理的测试方法,是否存在问题,听起来我没有考虑过?我应该嘲笑创建这个runnable的部分,然后自己测试runnable吗?或者我应该采取其他更好的途径吗?

注意:遗憾的是,我无法对我正在测试的代码进行任何修改。

2 个答案:

答案 0 :(得分:1)

看看ConcurrentUnit。它允许将任何线程中的断言和失败正确地报告回主测试线程,以便您的测试按预期通过或失败。

如果您无法控制可能失败的Runnable,您可以使用Thread.setDefaultUncaughtExceptionHandler来处理任何意外失败,让他们致电waiter.fail(throwable)

final Waiter waiter = new Waiter();

Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler(){
  @Override
  public void uncaughtException(Thread arg0, Throwable throwable) {
    waiter.fail(throwable);
  }
});

答案 1 :(得分:0)

如果不确切知道runnables中发生了什么,以及你是否可以重构它们,很难提供更多帮助。

也许您可以将侦听器传递给runnable以使其更易于测试。

public interface Listener {
   void onSuccess(Object context);
   void onError(Object context, Throwable t);
}

public class MyRunnable implements Runnable {
    private Listener listener;
    /// constructor;
    public void run() {
       Object context = ...;
       try {
          doStuff(context);
          listener.onSuccess(context);
       } catch (Throwable t) {
          listener.onError(context, t);
       }
    }
}

如果你无法重构runnable,你可以测试的唯一东西就是外部效果。如果这是一个单元测试而你已经实现了IOC,你可以模拟服务依赖关系并测试服务调用(例如使用Mockito)。