我正在使用JUnit和Mockito编写单元测试。我试图测试可运行块内部的逻辑。当捕获的参数不是流时,使用参数captor可以正常工作,但当参数是流时,错误为java.lang.IllegalStateException: source already consumed or closed
。我知道一旦try-catch
块完成,流将被关闭,但我们如何测试可运行块内部的逻辑?
下面是要测试的bean的逻辑:
...
@Transactional
public void execute() {
try (Stream<Object> data = jpaRepository.fetchStream()) {
Stream<Runnable> tasks = data.map(t -> () -> {
// logic to be tested goes here
});
someBean.method(tasks);
}
}
下面是单元测试
...
@InjectMocks
private App app;
@Mock
private SomeBean someBean;
@Captor
private ArgumentCaptor<Stream<Runable>> argumentCaptor;
@Test
void test() {
app.execute();
verify(someBean).method(argumentCaptor.capture());
argumentCaptor.getValue().findFirst().get().run(); // Here the error thrown: java.lang.IllegalStateException: source already consumed or closed
}
2条答案
按热度按时间khbbv19g1#
生成的
Stream
是惰性的,所以你必须确保它在someBean.method()
返回之前被消耗掉。解决方案取决于你的需要:最简单的解决方案是向bean传递一些不懒惰的东西,比如一个列表,只要在传递之前收集你的流就可以了。
如果这不是一个选项,你必须确保测试bean在方法被调用时立即进行收集,这应该可以通过子类或自定义模拟实现来实现。
jdgnovmf2#
为了简化问题,看一下这个例子。我们将流Map到流,然后将其存储在对象中。(这里是
StreamHolder
的情况,在您的情况下是ArgumentCaptor
)。正如你所看到的,流被存储在那里,然后关闭(当try with resources关闭时)。在那之后,如果我们尝试访问流的元素,我们将得到你提到的
IllegalStateException
:一个解决方案是不使用流来传递/存储数据。流主要是为了处理它们的元素。
因此,首先收集它们并传递Collection this
method
将更安全,并且它也会修复测试。