我试图将代理工作的代码单元测试到后台执行程序。在我重构了一个delete-method以返回id列表之后,我在单元测试中遇到了问题。当方法抛出sqlexception时应该验证行为的测试失败。
我以前没有在我的代码中使用过Futures,所以如果这个设计存在缺陷,请原谅我。
以下是我的代码。
TaskInteractor.java:
public class GetJStrainNameController : ApiController
{
[HttpGet]
public HttpResponseMessage GetName(??????)
{
我收到以下消息:
public class TaskInteractor extends AbstractInteractor
implements TaskContract.Interactor {
private final TaskRepository mRepository;
@Inject
public TaskInteractor(WorkerThread workerThread, MainThread mainThread, TaskRepository repository) {
super(workerThread, mainThread);
this.mRepository = repository;
}
...
@Override
@android.support.annotation.MainThread
public void deleteTasks(@NonNull final List<Task> tasks, @NonNull final DeleteTaskCallback callback) {
try {
final Future<List<String>> future = mWorkerThread.execute(() ->
mRepository.softDeleteAllInTransaction(tasks));
mMainThread.post(() -> {
try {
callback.onDeleteSuccess(future.get());
} catch (InterruptedException | ExecutionException e) {
Timber.e(e);
throw new RuntimeException(e.getCause());
}
});
} catch (final SQLiteAbortException e) {
mMainThread.post(() -> { callback.onAbortException(e); });
throw e;
} catch (final SQLiteConstraintException e) {
mMainThread.post(() -> { callback.onConstraintException(e); });
throw e;
} catch (final Exception e) {
mMainThread.post(() -> { callback.onFailure(e); });
throw new RuntimeException(e);
}
}
}
这是我的一项测试。
Wanted but not invoked:
mDeleteTaskCallbackMock.onAbortException(
<any android.database.sqlite.SQLiteAbortException>
);
-> at com.example.ui.task.ExaminationInteractorTest.whenDeleteFailWithSQLiteAbortException_shouldCallOnAbortFailureCallback(ExaminationInteractorTest.java:173)
However, there was exactly 1 interaction with this mock:
mDeleteTaskCallbackMock.onFailure(
java.lang.RuntimeException:
android.database.sqlite.SQLiteAbortException
);
-> at com.example.ui.examination.ExaminationInteractor.lambda$deleteExaminations$8(ExaminationInteractor.java:79)
执行由具有以下实现的测试双精度完成。
FakeWorkerThread.java:
@Test
public void whenDeleteFailWithSQLiteConstraintException_shouldCallOnConstraintFailureCallback() throws Exception {
doThrow(new SQLiteConstraintException()).when(mRepositoryMock).softDeleteAllInTransaction(ArgumentMatchers.<Task>anyList());
List<Task> tasks = Arrays.asList(TEST_TASKS);
mInteractor.deleteTasks(tasks, mDeleteTaskCallback);
verify(mDeleteTaskCallback).onConstraintException(
any(SQLiteConstraintException.class));
}
答案 0 :(得分:1)
在此代码段中:
try {
final Future<List<String>> future = mWorkerThread.execute(() ->
mRepository.softDeleteAllInTransaction(tasks));
mMainThread.post(() -> {
try {
callback.onDeleteSuccess(future.get()); // LINE 1
} catch (InterruptedException | ExecutionException e) {
Timber.e(e);
throw new RuntimeException(e.getCause()); // LINE 2
}
});
您正在向工作人员传递Callable
。其call()
引发的任何异常都将包含在ExecutionException
中,并存储在Future
中。
然后,当您致电future.get()
并且任务完成时,它将抛出ExecutionException
。
所以正在发生的事情如下:
future.get()
引发ExecutionException
包裹SQLiteConstraintException
(第1行); SQLiteConstraintException
包含在RuntimeException
(第2行); RuntimeException
与前两个catch子句不匹配,因此最终会在最后一次捕获中处理:catch (final Exception e) {}
; mDeleteTaskCallbackMock(RuntimeException)
被调用; 我建议您更改为以下:
try {
callback.onDeleteSuccess(future.get());
} catch (InterruptedException | ExecutionException e) {
Timber.e(e);
throw e.getCause(); //<--- throw the unwrapped exception
}