I have a class which has a Bean with @Qualifier (See AerospikeClient). While writing test cases, I am unable to mock the bean using @MockBean. I always get null pointer exception for aerospikeClient inside verify(aerospikeClient).put
My class
package com.a.recharge.service.impl;
import com.aerospike.client.*;
import com.aerospike.client.policy.WritePolicy;
import com.a.recharge.entity.aero.PacksInfo;
import com.a.recharge.service.AerospikeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class AerospikeServiceImpl implements AerospikeService {
@Autowired
@Qualifier("oldAerospikeClient")
private AerospikeClient aerospikeClient;
@Value("${config.aerospike.defaultNS:test}")
private String nameSpace;
@Value("${config.aerospike.set.txn:''}")
private String setname;
@Value("${config.aerospike.ttl:1800}")
private int ttl;
@Value("${config.aerospike.defaultNS}")
public String defaultNS;
@Value("${config.aerospike.host}")
private String aerospikeHost;
@Value("${config.aerospike.port}")
private String aerospikePort;
@Value("${config.aerospike.userName}")
public String aerospikeUserName;
@Value("${config.aerospike.password}")
public String aerospikePassword;
@Value("${config.aerospike.expiration}")
public long expiration;
@Value("${config.aerospike.expiration.no}")
public long noExpiration;
@Override
public void insertRecord(String keyString, PacksInfo packsInfo) {
// log.info("Saving Records in Aerospike, " keyString ", " packsInfo);
WritePolicy writePolicy = new WritePolicy();
writePolicy.expiration = ttl; // seconds
writePolicy.sendKey = true;
// columns
Bin[] bins = new Bin[3];
bins[0] = new Bin("type", packsInfo.getClass().getName());
bins[2] = new Bin("@user_key", keyString);
bins[1] = new Bin("value", packsInfo);
try {
Key key = new Key("test", "PacksInfo", keyString);
aerospikeClient.put(writePolicy, key, bins);
} catch (AerospikeException e) {
log.error("Exception raised. Root Cause {}, Message {}", ExceptionUtils.getRootCause(e),
ExceptionUtils.getMessage(e));
}
}
}
My test class
package com.a.recharge.service;
import com.aerospike.client.AerospikeClient;
import com.aerospike.client.Bin;
import com.aerospike.client.Host;
import com.aerospike.client.Key;
import com.aerospike.client.policy.ClientPolicy;
import com.aerospike.client.policy.WritePolicy;
import com.a.recharge.config.AerospikeConfiguration;
import com.a.recharge.service.impl.AerospikeServiceImpl;
import com.a.recharge.util.CollectionUtil;
import com.a.recharge.util.TestUtil;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.junit4.SpringRunner;
import org.testng.annotations.BeforeMethod;
import java.util.List;
import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals;
@RunWith(MockitoJUnitRunner.class)
// @SpringBootTest(classes = AerospikeServiceImpl.class)
public class AerospikeServiceImplTest {
@Mock(name ="oldAerospikeClient")
private AerospikeClient aerospikeClient;// = TestUtil.getAerospikeClient();
@Captor
private ArgumentCaptor<WritePolicy> captor1;
@Captor
private ArgumentCaptor<Key> captor2;
@Captor
private ArgumentCaptor<Bin[]> captor3;
@InjectMocks
// @Autowired
AerospikeServiceImpl aerospikeService;
// @BeforeMethod(alwaysRun = true)
// public void setUp() {
// MockitoAnnotations.initMocks(this);
// }
@Test
public void checkInsert(){
Mockito.doNothing().when(aerospikeClient).put(Mockito.any(), Mockito.any(), Mockito.any());
Mockito.verify(aerospikeClient).put(captor1.capture(), captor2.capture(), captor3.capture());
aerospikeService.insertRecord(TestUtil.keyString, TestUtil.getPacksInfo());
assertEquals(1800, captor1.getValue().expiration);
assertEquals(true, captor1.getValue().expiration);
}
}
i changed to InjectMocks and used Mockito.doNothing(), But still the same error. Is it because the put method of aerospikeClient is final?
Another question is that for testing the AerospikeServiceImpl class should I autowire it directly as above or create a bean like this?
@TestConfiguration
static class AerospikeServiceImplTestContextConfiguration {
@Bean
public AerospikeServiceImpl AerospikeServiceImpl() {
return new AerospikeServiceImpl();
}
}
I am relatively new to Spring Boot, so any best practices' advice will be highly appreciated.
My final test class. It works. No need of @TestConfiguration.
@RunWith(MockitoJUnitRunner.class)
public class AerospikeServiceImplTest {
@Mock //(name ="oldAerospikeClient")
private AerospikeClient aerospikeClient;
@Captor
private ArgumentCaptor<Key> captor2;
@InjectMocks
// @Autowired
private AerospikeServiceImpl aerospikeService;
@Test
public void checkInsert(){
aerospikeService.insertRecord(TestUtil.keyString, TestUtil.getPacksInfo());
Mockito.verify(aerospikeClient).put(captor1.capture(), captor2.capture(), captor3.capture());
assertEquals("test", captor2.getValue().namespace);
assertEquals("PacksInfo", captor2.getValue().setName);
assertEquals("MOBILE_JIOPREPAID_GJ", captor2.getValue().userKey.toString());
}
CodePudding user response:
aerospikeClient.put() is a final method. Mockito 2 now supports mocking final methods but this feature has to be explicitly activated ; it can be done via the mockito extension mechanism by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:
mock-maker-inline Please refer to this link: https://github.com/mockito/mockito/wiki/What's-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods