0

I am trying to mock dependencies inside my Spy object but mockito is not able to inject the mock objects as I am getting NullPointerException inside the Spy object.

My code is as follows:

@Component()
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class Target implements Target<InputPojo> {

    private final TargetHelper<InputPojo> inputHelper;

    @Override
    public List<ProcessedPojo> testMethod(List<InputPojo> inputs) throws someException {
        inputHelper.process(inputs);
         // ...further processing ...
        return processedList;
    }
}

@Component()
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class MyTargetHelper implements TargetHelper<InputPojo> {

    private final Map<SomeEnum, Double> someMap;

    private final AlertService alertService;

    private final DatabaseService databaseService;

    @Override
    public void process(List<InputPojo> inputs) throws SomeException {
        try {
            for (InputPojo i : inputs) {
                furtherProcess(databaseService.fetchForId(i.getId())); // Null pointer exception
            }
        } catch (SomeOtherException e) {
            alertService.raiseAlert("database error");
            throw(new SomeException());
        }
    }
}

@ExtendWith(MockitoExtension.class)
class TargetTest {

    @InjectMocks
    Target target;

    @Mock
    DatabaseService databaseService;

    @Mock
    AlertService alertService;

    @Spy
    Map<SomeEnum, Double> someMap = new EnumMap<>(SomeEnum.class);

    @Spy
    @InjectMocks
    MyTargetHelper inputHelper = new MyTargetHelper(someMap, alertService, databaseService);

    static final List<InputPojo> inputs;

    static {
        // add values to inputs and someMap
    }

    @Test
    @SneakyThrows
    void testTarget() {
        when(databaseService.fetchForId(anyString())).thenReturn("fetch success");

        target.testMethod(inputs);
    }
}

I have tried every other related question but none of them could solve my issue. I also tried changing

   private final TargetHelper<InputPojo> inputHelper;

to

   private final MyTargetHelper inputHelper;

but it didn't help. I have tried

I need to run Helper as part of my unit test in order to properly verify results of the TargetMethod, hence I want to Spy the method, however, I will need to mock the database service and alert service in order to make HelperMethod work properly.

CodeTalker
  • 1,683
  • 2
  • 21
  • 31
  • have you tried programmatically creating the mocks? Something like this: `someMap = Mokito.mock(AlertService.class); databaseService = Mokito.mock(DatabaseService.class);` Also, for data is better to use a real object and not a mock, therefore ` Map someMap` can be an actual map with some data for testing, – Emanuel Trandafir Mar 27 '23 at 08:29
  • Yes, for data like `someMap` I am making the actual Map. This map is configured as a bean and autowired by spring during actual run hence it is a dependency in the helper class. I need to inject this as dependency hence I am using @Spy on `someMap`. I didn't try making mocks proogramatically, let me try that as well and update here on the results. – CodeTalker Mar 27 '23 at 08:57
  • @EmanuelTrandafir Thanks, it magically worked! I wonder why Exactly the same code didn't work with Annotations while it worked programattically. However, one weird thing I observed here, while running the tests with coverage, none of the Lines of MyTargetHelper were shown as covered while during runtime, those lines were actually executed. Any pointers on this? – CodeTalker Mar 27 '23 at 09:08
  • i am not sure, maybe it is not clear to mockito where to inject the mock or maybe you cannot inject mocks into a spy (just an assumption). by the way, have you considered trying to use the real `MyTargetHelper` and only mock his dependencies? basically to remove the `@Spy` annotation? To inject it you can just pass it as a constructor argument, the same as you did when creating the `inputHelper ` – Emanuel Trandafir Mar 27 '23 at 09:36

0 Answers0