使用 Mockito Spy 对 ThreadPoolTaskExecutor 进行单元测试 InterruptedException
Unit Testing InterruptedException for ThreadPoolTaskExecutor with Mockito Spy
我正在使用 spring 的 ThreadPoolTaskExecutor
在多线程中执行任务。 class 如下所示
@Component
public class LoadData {
//... ...
@Inject
private ThreadPoolTaskExecutor taskExecutor;
public SomeData getData(Long id) {
Future<SomeData> loadData = taskExecutor.submit(() -> {
//return methodToGetDataSynchronously(id);
return new SomeData();
});
try {
SomeData data = loadData.get();
} catch (InterruptedException | ExecutionException e) {
logger.error("error");
//some more processing for the error here
}
return data;
}
}
为了能够对 class 进行单元测试并覆盖 InterruptedException
和 ExecutionException
分支,我尝试了多种方法(使用 Mockito
Spy
),但未能成功测试。
单元测试 class 如下所示:
@RunWith(MockitoJUnitRunner.class)
public class LoadDataTest {
@InjectMocks
private LoadData loadData;
@Spy
private ThreadPoolTaskExecutor spyTaskExecutor = new ThreadPoolTaskExecutor();
@Before
public void init() {
MockitoAnnotations.initMocks(this);
spyTaskExecutor.setCorePoolSize(1);
spyTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
spyTaskExecutor.initialize();
}
@Test
public void testGetData_shouldThrowInterruptedException () {
Mockito.when(spyTaskExecutor.submit(Matchers.<Callable<SomeData>>any())).thenAnswer(new Answer<Future<SomeData>>() {
public Future<SomeData> answer(InvocationOnMock invocation) throws Throwable {
Future<SomeData> future = Mockito.mock(FutureTask.class);
when(future.isDone()).thenReturn(false, false, true);
when(future.get()).thenThrow(new InterruptedException ());
return future;
}
});
SomeData result = null;
result = loadData.getData(101L);
//verify here that InterruptedException processing was performed
}
}
我将 Spy
用于 ThreadPoolTaskExecutor
,因为我在测试中有其他方法可以测试多线程执行的实际行为。
当我尝试 运行 测试方法时,它会在 stubbing spy 上抛出 NullPointerException
:
Mockito.when(spyTaskExecutor.submit(Matchers.<Callable<SomeData>>any()))...
异常:
java.lang.NullPointerException
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:132)
at org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor.submit(ThreadPoolTaskExecutor.java:320)
at com.company.LoadDataTest.testGetData_shouldThrowInterruptedException(LoadDataTest.java:20)
我想,问题可能出在我对 Mockito Spy 进行 stub 处理的方式上。但是,我不确定我是否在正确的路径上存根 InterruptedException
。有没有人得到如何实现这一目标的示例?
版本:
jdk-1.8.0_72
junit-4.12
mockito-core-1.10.19
spring-context-4.3.4.RELEASE
注意:这是实际代码的摘录。实际代码执行许多其他事情,并注入了许多其他 bean - 其中一些是 Test
中的 Mock
,一些是 Spy
- 取决于我正在测试的内容。我这里只提到了我遇到问题的部分。
终于找到问题了。我真的很接近,只是 Mockito Spy 的使用有点偏离。这是有效的解决方案:
@RunWith(MockitoJUnitRunner.class)
public class LoadDataTest {
@InjectMocks
private LoadData loadData;
@Spy
private ThreadPoolTaskExecutor spyTaskExecutor = new ThreadPoolTaskExecutor();
@Before
public void init() {
MockitoAnnotations.initMocks(this);
spyTaskExecutor.setCorePoolSize(1);
spyTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
spyTaskExecutor.initialize();
}
@Test
public void testGetData_shouldThrowInterruptedException () {
setupSpyTaskExecutorForException(new InterruptedException("junit"));
SomeData result = loadData.getData(101L);
//verify here that InterruptedException processing was performed
}
private void setupSpyTaskExecutorForException(Exception e) {
Mockito.doAnswer(new Answer<Future<?>>() {
public Future<?> answer(InvocationOnMock invocation) throws Throwable {
Future<?> future = Mockito.mock(FutureTask.class);
when(future.get()).thenThrow(e);
return future;
}
}).when(spyTaskExecutor).submit(Matchers.<Callable<?>>any());
}
}
我正在使用 spring 的 ThreadPoolTaskExecutor
在多线程中执行任务。 class 如下所示
@Component
public class LoadData {
//... ...
@Inject
private ThreadPoolTaskExecutor taskExecutor;
public SomeData getData(Long id) {
Future<SomeData> loadData = taskExecutor.submit(() -> {
//return methodToGetDataSynchronously(id);
return new SomeData();
});
try {
SomeData data = loadData.get();
} catch (InterruptedException | ExecutionException e) {
logger.error("error");
//some more processing for the error here
}
return data;
}
}
为了能够对 class 进行单元测试并覆盖 InterruptedException
和 ExecutionException
分支,我尝试了多种方法(使用 Mockito
Spy
),但未能成功测试。
单元测试 class 如下所示:
@RunWith(MockitoJUnitRunner.class)
public class LoadDataTest {
@InjectMocks
private LoadData loadData;
@Spy
private ThreadPoolTaskExecutor spyTaskExecutor = new ThreadPoolTaskExecutor();
@Before
public void init() {
MockitoAnnotations.initMocks(this);
spyTaskExecutor.setCorePoolSize(1);
spyTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
spyTaskExecutor.initialize();
}
@Test
public void testGetData_shouldThrowInterruptedException () {
Mockito.when(spyTaskExecutor.submit(Matchers.<Callable<SomeData>>any())).thenAnswer(new Answer<Future<SomeData>>() {
public Future<SomeData> answer(InvocationOnMock invocation) throws Throwable {
Future<SomeData> future = Mockito.mock(FutureTask.class);
when(future.isDone()).thenReturn(false, false, true);
when(future.get()).thenThrow(new InterruptedException ());
return future;
}
});
SomeData result = null;
result = loadData.getData(101L);
//verify here that InterruptedException processing was performed
}
}
我将 Spy
用于 ThreadPoolTaskExecutor
,因为我在测试中有其他方法可以测试多线程执行的实际行为。
当我尝试 运行 测试方法时,它会在 stubbing spy 上抛出 NullPointerException
:
Mockito.when(spyTaskExecutor.submit(Matchers.<Callable<SomeData>>any()))...
异常:
java.lang.NullPointerException
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:132)
at org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor.submit(ThreadPoolTaskExecutor.java:320)
at com.company.LoadDataTest.testGetData_shouldThrowInterruptedException(LoadDataTest.java:20)
我想,问题可能出在我对 Mockito Spy 进行 stub 处理的方式上。但是,我不确定我是否在正确的路径上存根 InterruptedException
。有没有人得到如何实现这一目标的示例?
版本:
jdk-1.8.0_72
junit-4.12
mockito-core-1.10.19
spring-context-4.3.4.RELEASE
注意:这是实际代码的摘录。实际代码执行许多其他事情,并注入了许多其他 bean - 其中一些是 Test
中的 Mock
,一些是 Spy
- 取决于我正在测试的内容。我这里只提到了我遇到问题的部分。
终于找到问题了。我真的很接近,只是 Mockito Spy 的使用有点偏离。这是有效的解决方案:
@RunWith(MockitoJUnitRunner.class)
public class LoadDataTest {
@InjectMocks
private LoadData loadData;
@Spy
private ThreadPoolTaskExecutor spyTaskExecutor = new ThreadPoolTaskExecutor();
@Before
public void init() {
MockitoAnnotations.initMocks(this);
spyTaskExecutor.setCorePoolSize(1);
spyTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
spyTaskExecutor.initialize();
}
@Test
public void testGetData_shouldThrowInterruptedException () {
setupSpyTaskExecutorForException(new InterruptedException("junit"));
SomeData result = loadData.getData(101L);
//verify here that InterruptedException processing was performed
}
private void setupSpyTaskExecutorForException(Exception e) {
Mockito.doAnswer(new Answer<Future<?>>() {
public Future<?> answer(InvocationOnMock invocation) throws Throwable {
Future<?> future = Mockito.mock(FutureTask.class);
when(future.get()).thenThrow(e);
return future;
}
}).when(spyTaskExecutor).submit(Matchers.<Callable<?>>any());
}
}