Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/wcf/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 如何验证JUnit中模拟方法的顺序_Android_Junit_Mockito - Fatal编程技术网

Android 如何验证JUnit中模拟方法的顺序

Android 如何验证JUnit中模拟方法的顺序,android,junit,mockito,Android,Junit,Mockito,我有一个具有这些结构的类,我需要测试onrequestlistofluncsfinished接口的行为 @Override public void getListOfLunchs(final OnRequestListOfLunchsFinished callback) { zip().onErrorResumeNext(new Function<Throwable, ObservableSource<? extends LunchServiceResponse>&g

我有一个具有这些结构的类,我需要测试
onrequestlistofluncsfinished
接口的行为

@Override
public void getListOfLunchs(final OnRequestListOfLunchsFinished callback) {

    zip().onErrorResumeNext(new Function<Throwable, ObservableSource<? extends LunchServiceResponse>>() {

        @Override
        public ObservableSource<? extends LunchServiceResponse> apply(@NonNull Throwable throwable) throws Exception {
            callback.onError(new RuntimeException(throwable));
            callback.onEnd();

            return Observable.empty();
        }

    }).subscribe(new Consumer<LunchServiceResponse>() {

        @Override
        public void accept(LunchServiceResponse response) throws Exception {
            List<Lunch> result = new ArrayList<>();

            List<IngredientResponseVO> ingredients = response.getIngredients();
            Map<Integer, Ingredient> hash = new HashMap<Integer, Ingredient>();

            for (IngredientResponseVO vo : ingredients)
                hash.put(vo.id, new Ingredient(vo.id, vo.name, new BigDecimal(vo.price.toString()), vo.image));

            for(InfoLunchResponseVO vo: response.getLunch()){
                Lunch lunch = new Lunch();
                lunch.setId(vo.id);
                lunch.setImage(vo.image);
                lunch.setName(vo.name);

                for(Integer id : vo.ingredients){
                    Ingredient ingredient = hash.get(id);
                    lunch.addIngredient(ingredient);
                }

                result.add(lunch);
            }

            callback.onSuccess(result);
            callback.onEnd();
        }

    });

    callback.onStart();
}

private Observable<LunchServiceResponse> zip(){
    return Observable.zip(getRequestOfListOfLunchs(), getRequestOfListOfIngredients(), new BiFunction<List<InfoLunchResponseVO>, List<IngredientResponseVO>, LunchServiceResponse>() {

        @Override
        public LunchServiceResponse apply(@NonNull List<InfoLunchResponseVO> infoLunchResponseVOs, @NonNull List<IngredientResponseVO> ingredientResponseVOs) throws Exception {
            return new LunchServiceResponse(infoLunchResponseVOs, ingredientResponseVOs);
        }

    });
}
@覆盖
public void getListOfLunchs(最终OnRequestListOfLunchsFinished回调){

zip().onErrorResumeNext(新函数您只需使用
顺序对象即可

mockImplementation.getListOfLunchs(callback);

Mockito.verify(callback).onStart();
Mockito.verify(callback).onSuccess(anyList());
Mockito.verify(callback).onEnd();

Mockito.verifyNoMoreInteractions();

AFAICS问题不在于测试,而在于您对测试结果的阅读(向前跳:我相信它在您的代码中发现了一个bug)

可能在真实代码中,您的
getListOfIngredients
getLiunts
执行一些网络请求,即它们与调用
getListOfLunchs
和(
zip
内部)是异步的因此,在真正的代码中,
onStart
会在调用线程上立即调用,而
onsuces
onEnd
会在稍后调用。但是,在测试中,您模拟这些API调用时,可以观察到非常同步的
。只要
,执行顺序就不同了:首先
onSuccess
调用,然后是
onEnd
,最后是
onStart
(如果您将模拟的
回调
替换为只在每次调用中记录方法名称的自定义回调,则可以轻松验证这一点)

您可能已经体验到,由于您使用了
verifyNoMoreInteractions
,您可能会得到一个关于
onStart
的错误顺序的错误。不幸的是,这不是它的工作方式。由于您的订单验证是在更早的时候指定的,所以它们会在更早的时候被检查。在这些检查中,还没有“不再”的限制.因此,发生的情况大致如下:

  • 调用了
    onsuces
    inoder
    check忽略它,因为还没有
    onStart
  • onEnd
    被调用。
    inoder
    check忽略它,因为还没有启动
    onStart
  • 调用了
    onStart
    。这与
    InOrder
    期望的匹配,现在它等待
    onSucess
    。但是这(第二次)
    onSuccess
    从未出现,这正是错误所说的
  • 那么该怎么办呢?首先我想说的是,这次失败的测试确实在你的代码中发现了一个非常真实的错误。假设在将来的某个时候,有人在你的API中添加了一个缓存层,所以有时候
    getListofIngreents
    getLiunts
    会立即返回同步结果。在这种情况下,你的代码会中断在
    onrequestlistofluncsfinished
    中,应该首先调用
    onStart
    。因此正确的方法是修复代码。一个明显但可能错误的方法是移动行

    callback.onStart();
    

    方法的开头。(为什么可能出错?您的
    zip
    能否引发异常?如果引发异常,则
    回调的状态会发生什么变化?)。另一种方法是与使用ONED时相同,即按正确顺序将其复制到成功和错误处理代码中。

    但在这种情况下,调用顺序很重要:/
    callback.onStart();
    callback.onSuccess(Collections.<Lunch>emptyList());
    callback.onEnd();
    
    InOrder order = inOrder(callback);
    
    order.verify(callback).onStart();
    order.verify(callback).onSuccess(anyList());
    order.verify(callback).onEnd();
    
    order.verifyNoMoreInteractions();
    
    mockImplementation.getListOfLunchs(callback);
    
    Mockito.verify(callback).onStart();
    Mockito.verify(callback).onSuccess(anyList());
    Mockito.verify(callback).onEnd();
    
    Mockito.verifyNoMoreInteractions();
    
    callback.onStart();