Unable to mock MongoTemplate executeQuery using Mockito

Viewed 4053

I'm looking to mock MongoTemplate, so that the executeQuery function in my service can be actually get called. This is how my service code block looks like:

 this.mongoTemplate.executeQuery(query, collectionName, new DocumentCallbackHandler() {

            @Override
            public void processDocument(Document document) throws MongoException, DataAccessException {
                try {
                    // convert to strongly typed object
                  System.out.println("Actual method called");
                    ProductDayData pdd = mongoTemplate.getConverter().read(ProductDayData.class, document);

                    // call copyover
                    backFillOneEvent(pdd, liveContractIds, pddType, toDate, now, timeAtStartOfDay);
                } catch (RuntimeException e) {
                    LOGGER.error("FATAL: backfill - error processing document: {}", document, e);
                } catch (Throwable t) {
                    LOGGER.error("FATAL: backfill - error processing document: {}", document, t);
                    throw t;
                }
            }

        });

In my unit test, this is what I've done:

@Mock
  private MongoTemplate mongoTemplate;

service = new MyService(mongoTemplate); //mock is set
Mockito.doCallRealMethod().when(mongoTemplate).executeQuery(Mockito.any(Query.class),Mockito.any(String.class),Mockito.any(DocumentCallbackHandler.class));

The doCallRealMethod() apparently doesn't do anything, I expected it to trigger the actual method.

1 Answers

You need to use Spy instead of Mock.

MongoTemplate mongoTemplate = Mockito.spy(
    //Instance the MongoTemplate, use any test framework
    new MongoTemplate(new SimpleMongoClientDbFactory("mongodb://localhost/test"))
);
// Since it's spy, by default, it will execute real method
//Skipping stub Mockito.doCallRealMethod()....

System.out.println("Real");
mongoTemplate.executeQuery(query, collectionName, new DocumentCallbackHandler() {

        @Override
        public void processDocument(Document document) throws MongoException, DataAccessException {
            //Simplified version
            System.out.println("Actual method called:" + document.toJson());
        }

    });
System.out.println("End Real");

//Now call fake `executeQuery`
Mockito.doNothing().when(mongoTemplate).executeQuery(Mockito.any(Query.class), Mockito.any(String.class),
            Mockito.any(DocumentCallbackHandler.class));
System.out.println("Mock");
mongoTemplate.executeQuery(query, collectionName, new DocumentCallbackHandler() {

        @Override
        public void processDocument(Document document) throws MongoException, DataAccessException {
            //Simplified version
            System.out.println("Actual method called:" + document.toJson());
        }

});
System.out.println("End Mock");

//Now we "enable" real method call  
Mockito.doCallRealMethod().when(mongoTemplate).executeQuery(Mockito.any(Query.class), Mockito.any(String.class),
        Mockito.any(DocumentCallbackHandler.class));
System.out.println("Real 2");
mongoTemplate.executeQuery(query, collectionName, new DocumentCallbackHandler() {

    @Override
    public void processDocument(Document document) throws MongoException, DataAccessException {
        System.out.println("Actual method called:" + document.toJson());
    }

});
System.out.println("End Real 2");

--Output---

Real
//MongoDB traces...
Actual method called:{...}
Actual method called:{...}
...
End Real
Mock
End Mock
Real 2
//MongoDB traces...
Actual method called:{...}
Actual method called:{...}
...
End Real 2

Links: @Mock vs @Spy

Related