没有 setPk() 时模拟 getPk() 函数

Mocking getPk() function when there is no setPk()

我有以下代码(Facade 的一小部分)要在单元测试中覆盖。我正在使用 Mockito 模拟属于服务层的函数。

Iterator<AbstractOrderEntryModel> entryModelItr = orderEntryModelList.iterator();
            while (entryModelItr.hasNext()) {

                AbstractOrderEntryModel entryModel = entryModelItr.next();

                if (CollectionUtils.isNotEmpty(deletedPKList) && deletedPKList.contains(entryModel.getPk().toString())) {
                    entryModelItr.remove();
                    modelService.remove(entryModel);
                }

            }

我一直在通过调用要测试的函数并提供具有设置值的输入来编写测试用例,以便可以实现代码的最大覆盖率(如果这不是它应该完成的方式,请纠正我)。

我的问题是我的函数 entryModel.getPk() 没有 setter,例如。 entryModel.setPk() 我可以打电话。结果它会在这一行抛出一个空指针异常。我不想模拟 entryModel 对象。怎么办?

(Pk就像那个模型的主键class。整个代码是在Hybris平台上写的)

如果您使用真实对象测试真实系统,那么缺少主键将会产生真实的后果。最好的 "seams" 测试是覆盖模型 class,提取对它的调用以便将其外部化,或者监视真实对象。我强烈建议在重构时考虑到测试,但您确实有一些选项对生产的影响为零或最小。


一个解决方案是创建您自己的 AbstractOrderEntryModel 的具体子class,可能称为 FakeOrderEntryModel,它具有您想要的构造函数。我认为这是更好的方法,特别是因为它不会改变被测系统。

另一个需要最少更改的解决方案是将 entryModel.getPk().toString() 提取到被测系统上的可覆盖 protected 方法。在您的测试中,覆盖该方法以提供基于地图的查找。重 OOP 解决方案是在策略模式中创建 "PkGetter" class(使用单个 getPk(AbstractOrderEntryModel model) 方法)并提供用于测试的替代实现;这可能有点矫枉过正了。

最后,要使用真实的数据对象但仅覆盖其上的一两个方法,请使用 spy:

AbstractOrderEntryModel model = spy(new ConcreteOrderEntryModel(...));
doReturn(42).when(model).getPk();

考虑到这个问题已有 5 年历史,如果有人仍然对 Jeff Bowman 的上述解决方案是否有效感到好奇,那么下面的解决方案对我有用。

private AbstractOrderEntryModel abstractOrderEntryModel = new AbstractOrderEntryModel (){
    @Override
    public PK getPk() {
        return de.hybris.platform.core.PK.BIG_PK;
    }
};

猜猜我在监视模型对象时做错了什么,但是,重写 getPk() 方法为我完成了工作。