Mockito:检测何时调用私有资源上的方法

时间:2017-06-27 15:06:19

标签: java mockito

我需要为这个班写一个测试。我需要验证当列表的大小正好是2时,调用modelService.save。是否也可以访问对象productModel?

我不知道从哪里开始。

public class SoldMaterialPrepareInterceptor implements PrepareInterceptor<SoldMaterialModel> {

    @Resource
    private ModelService modelService;

    @Override
    public void onPrepare(SoldMaterialModel soldMaterialModel, InterceptorContext interceptorContext) throws InterceptorException {
            setSAPSubstance(soldMaterialModel);
    }

    private void setSAPSubstance(SoldMaterialModel soldMaterialModel) {
        ProductModel productModel = soldMaterialModel.getBaseProduct();
        Set superCatagoriesList = [....]// gets the list somehow
        if (superCatagoriesList.size() == 2) {
            productModel.setSupercategories(superCatagoriesList);
            modelService.save(productModel);
        }
    }
}

3 个答案:

答案 0 :(得分:1)

modelService字段是私有的并不是问题,它是一个通常需要私有访问修饰符的类字段。您需要检查其save()方法的调用,而该方法又不能是私有的,否则无法从拦截器类中调用它。

对于测试,假设superCatagoriesList(实际上是Set而不是List并且也应该是通用的)从soldMaterialModel参数直接或间接(例如通过productModel)获取其内容,您的任务是编写测试,使用这样的值填充soldMaterialModel,以便superCatagoriesList.size()为2,然后您可以验证modelService.save()方法是否被调用一次,例如

之类的东西
Mockito.verify(modelService).save(any(ProductModel.class));

答案 1 :(得分:1)

我发现当最难测试方法时,我正在测试的代码存在设计问题。我建议首先重构一下:将setSAPSubstance移动到SoldMaterialModel类并将其公开。这就是该方法所需要的地方(见feature envy)。当然input将留在拦截器中,只有在需要时才会调用它。 那么你只需要测试两个公共方法

答案 2 :(得分:1)

那是全班吗?然后我想我看到了这个问题。没有非私有方式来设置ModelService。当整个app运行时,依赖注入框架使用反射来设置ModelService。当你进行测试时,你无论如何也无法注入模拟。你有几个选择。

您可以向SoldMaterialPrepareInterceptor添加构造函数,该构造函数将ModelService作为参数。然后你可以在测试中使用它。您可能还需要添加无参数构造函数,因为这是您的依赖注入框架如何创建它。更好的是,您可以弄清楚如何配置框架以使用采用ModelService的新构造函数。

public class SoldMaterialPrepareInterceptor {
    // Public constructor if needed for dependency injection
    public SoldMaterialPrepareInterceptor () { }

    // If just used for test use protected or package private
    // If used with dependency injection, use public.
    protected SoldMaterialPrepareInterceptor(ModelService modelService){
        this.modelService = modelService
    }

测试类通常与实际类在同一个包中,因此包私有或受保护的范围就足够了。然后测试看起来像这样(假设Mockito和Junit。逻辑上,Spock和其他框架会类似):

ModelService modelService = Mockito.mock(ModelService.class);
SoldMaterialPrepareInterceptor interceptor = new SoldMaterialPrepareInterceptor(modelService);
// setup SoldMaterialModel and InterceptorContext
interceptor.onPrepare(soldMaterialModel, interceptorContext);
Mockito.verify(modelService, Mockito.times(0)).save(soldMaterialModel);