2

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.

rishabh
  • 1,155
  • 1
  • 10
  • 17
  • `@Mock` creates `a bare-bones shell instance`, so it can't call real method... Try to use `@Spy` – Valijon Jun 15 '20 at 12:16

1 Answers1

1

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

Valijon
  • 12,667
  • 4
  • 34
  • 67
  • I had one question - The Mockito.spy( //Instance the MongoTemplate, use any test framework new MongoTemplate(new SimpleMongoClientDbFactory("mongodb://localhost/test")) ); doesn't work in the CI/CD setup. Does this mean we have to have a local Mongo running on the build server? – rishabh Jun 15 '20 at 21:38
  • @rishabh No. You can use `Fongo` / [flapdoodle](https://stackoverflow.com/questions/29587430/spring-data-mongodb-junit-test) – Valijon Jun 15 '20 at 22:58