Search code examples
unit-testingjunitmockitosap-commerce-cloudpowermockito

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


I have the following piece of code (a small part of a Facade) to cover in unit tests. I am using Mockito to mock functions belonging to a service layer.

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);
                }

            }

I have been writing test cases by calling the function to be tested and providing inputs with set values so that maximum coverage can be achieved of the code (Correct me if that is not the way its supposed to be done).

My question is that I have function entryModel.getPk() for which there is no setter, for eg. entryModel.setPk() that I can call. It will throw a null pointer exception in this line as a result. I don't want to mock the entryModel object. How to go about it?

(Pk is like a PrimaryKey for that model class. The whole code is written on the Hybris platform)


Solution

  • If you test a real system with a real object, then the lack of primary key is going to have real consequences. Your best "seams" for testing are to override your Model class, extract out your call to it so you can externalize it, or spy on a real object. I highly recommend refactoring with testing in mind, but you do have some options with zero or minimal effect in production.


    One solution is to create your own concrete subclass of AbstractOrderEntryModel, presumably called FakeOrderEntryModel, that has the constructor you desire. I think that's the preferable method here, particularly because it doesn't change the system under test.

    Another solution that would require minimal change is to extract entryModel.getPk().toString() to an overridable protected method on your system under test. In your test, override that method to provide a Map-based lookup. A heavy-OOP solution would be to create a "PkGetter" class in the Strategy pattern (with a single getPk(AbstractOrderEntryModel model) method) and provide an alternative implementation for testing; that's probably overkill here.

    Finally, to use a real data object but to override only one or two methods on it, use a spy:

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