【问题标题】:How to test class which implements Runnable with Junit如何使用 Junit 测试实现 Runnable 的类
【发布时间】:2018-11-12 21:05:17
【问题描述】:

我有一个类像这样实现 Runnable

  public Processor implements Runnable{

  public void run() {
     while (true) {
     //some code
     sendRequest(object);
      }
   }
}

 public void sendRequest(Object, object){
 // do something to send the event
  }
}

在其他预加载类中。我用

Processor processor = new Processor();
ExecutorService executor = Executors.newCachedThreadPool();
executor.execute(processor)

所以我的问题是如何单元测试 sendRequest 方法是否被调用?

【问题讨论】:

  • sendRequest 发送东西到哪里?从示例中不清楚。通常,我会注入/获取一个模拟目标,该目标可以向测试类报告成功/失败,并具有适当的超时时间。某种程度上,类似于greenmail支持邮件测试的方式。

标签: java multithreading unit-testing junit


【解决方案1】:

分离关注点:Runnable 和关联的逻辑。
此外,它还会使您的代码模式可测试。
您可以在 Foo 类中提取 sendRequest() Processor 类所依赖的类。 然后,您只需在测试中模拟这个 Foo 类并验证是否调用了 sendRequest() 方法。

例如:

 public Processor implements Runnable{

  private Foo foo;

  public Processor(Foo foo){
    this.foo = foo;
  }

  public void run() {
     while (true) {
       //some code
       foo.sendRequest(object);
     }
   }
}

还有测试:

@Mock
Foo fooMock;

@Test
public void run() {
    Processor processor = new Processor(fooMock);
    ExecutorService executor = Executors.newCachedThreadPool();
    executor.execute(processor);
    executor.awaitTermination(someTime, TimeUnit.SECONDS);
    Mockito.verify(fooMock).sendRequest(...);   
}

【讨论】:

  • +1,我也在想同样的事情。让run() 委托给一个方法要好得多,这样在没有 Runnable 使其更复杂的情况下更容易测试。它不会为您提供 100% 的覆盖率,但值得权衡
  • @Jimmy 确实复杂的不可测试的类真的很烦人。并且使用 PowerMock 或部分模拟是个人没有办法的。但是为什么你认为这样的重构会损害覆盖率?
  • @davidxxx 所以我得把sendRequest方法提取到另一个类进行单元测试?
  • 没错。一个理智的重构。
  • 我们应该关闭 executorService。 executor.execute(处理器); executor.shutdown); executor.awaitTermination(someTime, TimeUnit.SECONDS);
【解决方案2】:

我相信您只想测试已实现的run() 方法,因此您可以使用Processor 对象直接调用该方法,或者您可以创建一个线程并将可运行对象传递给它并调用Thread.start()

如果sendRequest(Object object) 方法正在执行任何外部操作,我建议您模拟该方法

public class ThreadTest {

@Test(//throws some exception)
public void shouldThrowSomeException() {
    Processor exThread = new Processor ();
    exThread.run(); //or
    Thread t = new Thread(exThread);
     t.start()

    }
}

Mocking 用于模拟 here

@Test(//throws some exception)
public void shouldThrowSomeException() {
    Processor exThreadmock = mock(Processor.class);
    when(exThreadmock.sendRequest(anyObject))
    .thenThrow(SomeException.class)
    Thread t = new Thread(exThread);
     t.start()

    }

【讨论】:

    【解决方案3】:

    使用Mockito.spy 进行部分模拟。

    Processor processor = spy(new Processor());
    
    doCallRealMethod().when(processor).run();
    
    verify(processor).sendRequest(mock1, mock2);
    

    【讨论】:

    • 我按照您的步骤操作,但未调用 sendRequest 方法
    猜你喜欢
    • 2015-11-03
    • 1970-01-01
    • 1970-01-01
    • 2019-04-18
    • 1970-01-01
    • 2020-02-10
    • 1970-01-01
    • 1970-01-01
    • 2022-11-23
    相关资源
    最近更新 更多