Wrong
Wrong

Reputation: 1253

Spring boot - Can't mock MongoTemplate

I have a method in a service that I want to test and which uses MongoTemplate as follows:

@Service
public class MongoUpdateUtilityImpl implements MongoUpdateUtility {
    private final MongoTemplate mongoTemplate;
    
    @Autowired
    MongoUpdateUtilityImpl (final MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

    @Override
    public Object update(final String id, final Map<String, Object> fields, final Class<?> classType) {
        ...
        this.mongoTemplate.updateFirst(query, update, classType);
        return this.mongoTemplate.findById(id, classType);
    }       
}

Then I'm trying to test this method with mocked methods for mongo template:

@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("test")
public class MongoUpdateUtilityTest {
    @MockBean
    private MongoTemplate mongoTemplate;

    @Autowired
    private MongoUpdateUtility mongoUpdateUtility;

    /**
     * Test en el que se realiza una actualización correctamente.
     */
    @Test
    public void updateOK1() {
        final Map<String, Object> map = new HashMap<>();

        map.put("test", null);
        map.put("test2", "value");

        when(mongoTemplate.updateFirst(Mockito.any(Query.class), Mockito.any(Update.class), Mockito.any(Class.class)))
                .thenReturn(null);
        when(mongoTemplate.findById(Mockito.anyString(), Mockito.any(Class.class))).thenReturn(null);

        assertNull(this.mongoUpdateUtility.update("2", map, Map.class));
    }
}

I have read this question but when I try the answer marked as solution, it says that MongoTemplate cannot be initialized. I'd prefer to mock this than to use and embebded database since I'm limited on the libraries that I can use.

My error:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'operacionesPendientesRepository' defined in es.santander.gdopen.operpdtes.repository.OperacionesPendientesRepository defined in @EnableMongoRepositories declared on MongoRepositoriesRegistrar.EnableMongoRepositoriesConfiguration: Invocation of init method failed; nested exception is java.lang.NullPointerException

Upvotes: 5

Views: 10128

Answers (2)

Mr. Anderson
Mr. Anderson

Reputation: 1555

If you don't need to process the "real" mongoTemplate (when you just need to test the business inside the method without real data persistence) you may use "deep mock" through the following config in Mockito:

@Mock(answer = Answers.RETURNS_MOCKS)
private MongoTemplate mongoTemplate

Then calls like these can be done (mocked) with no problem:

List<Entity> listResult = mongoTemplate.query(Entity.class)
            .matching(query.with(Sort.by("anyField")))
            .all();

This is specially usefull when you need to test code that uses third-part framework objects that cannot be "created" manually.

Upvotes: 1

Lesiak
Lesiak

Reputation: 25936

You are using @SpringBootTest which brings up entire application context. This means every bean defined in your app will be initialized.

This is an overkill for a test of a @Service:

  • your test will take longer to execute
  • entire context must be correct

For a test of a @Service, I advise you to take a simpler approach and test the service in isolation.

  • use Mockito extension / runner (depending on junit version)
  • get rid of @SpringBootTest, @ActiveProfiles and SpringRunner
  • use @Mock instead of @MockBean
  • use @InjectMocks instead of @Autowired

Upvotes: 7

Related Questions