Mock not initiated on Static method - junit

I am facing issues in mocking static method.
Below is my code where I am calling a static method
public class GetAllBatches {
public HttpResponseMessage run(
#HttpTrigger(route = "v1/batches",
name = "request",
methods = {HttpMethod.GET},
authLevel = AuthorizationLevel.ANONYMOUS)
HttpRequestMessage<String> request,
final ExecutionContext context){
context.getLogger().info("List batches Called");
String apiResponse ;
String connector = request.getQueryParameters().getOrDefault("connector", "");
try{
BatchesController batchesController = BatchesController.getInstance();
apiResponse = new Gson().toJson(batchesController.getBatches(connector));
}
}
}
BatchesController Class :
public class BatchesController {
Logger log = Logger.getLogger(BatchesController.class.getName());
public static BatchesController getInstance() {
if (batchesController == null) {
batchesController = new BatchesController(BatchDaoFactory.getDao());
}
return batchesController;
}
private static BatchesController batchesController = new BatchesController();
private final BatchDao batchDao;
public BatchesController(BatchDao BatchDao) {
this.batchDao = BatchDao;
}
// Do something
}
And below is the test that I have :
#RunWith(MockitoJUnitRunner.class)
public class GetAllBatchesTest {
#Mock
ExecutionContext context;
#Mock
HttpRequestMessage<String> request;
#Mock
BatchesController batchesController;
#Mock
BatchDao BatchDao;
#InjectMocks
GetAllBatches getAllBatchesMock = new GetAllBatches();
#Before
public void setUp() {
Map<String, String> map = new HashMap<>();
map.put("connector", "");
doReturn(Logger.getGlobal()).when(context).getLogger();
doReturn(map).when(request).getQueryParameters();
try (MockedStatic<BatchesController> utilities = Mockito.mockStatic(BatchesController.class)) {
utilities.when(BatchesController::getInstance).thenReturn(batchesController);
}
doAnswer((Answer<HttpResponseMessage.Builder>) invocationOnMock -> {
HttpStatus status = (HttpStatus) invocationOnMock.getArguments()[0];
return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status);
}).when(request).createResponseBuilder(any(HttpStatus.class));
}
#Test
public void testHttpTriggerJava() {
final HttpResponseMessage ret = getAllBatchesMock.run(request, context);
Assertions.assertEquals(ret.getStatus(), HttpStatus.OK);
}
When I run my test, it throws an error message :
java.lang.ExceptionInInitializerError
BatchesController.getInstance() is not actually returning the mock value.
I am not sure what is going wrong here ?
UPDATE :
I found out that the problem is because I am using Mockito-inline Mockito-inline fails to initiate mock on class but initiates mock only on interfaces

You are using a try-with-resources block to setup a static mock:
try (MockedStatic<BatchesController> utilities = Mockito.mockStatic(BatchesController.class)) {
utilities.when(BatchesController::getInstance).thenReturn(batchesController);
}
Remember that the static mock is only active in scope of the block - after you exit the block the resource is closed.
Thus, you need to:
move the static mock initialization from setup method to the test method
run code under test within the try-with-resources block

Related

Junit Mockito for global java.util.Map

I am trying to Test a method but it has a global variable which is null, Please guide me so I can assign value to global variable i.e. a Map
My Junit:
public class ErrorTest {
#Mock
private DataSource db;
#Mock
private JdbcTemplate jdbcTemplate;
#InjectMocks
private RateServiceImpl rateService = new RateServiceImpl();
#Mock
private RaterDao raterDao;
#Resource
private MessageSource msg ;
#Mock
Map<String, StringAttribute> errorMap = new HashMap<String, StringAttribute>();
#Before
public void setup() throws IOException, InterruptedException {
MockitoAnnotations.initMocks(this);
MockMvcBuilders.standaloneSetup(rateService).build();
}
#Test
public void findAllErrors() throws Exception {
String error;
List<Error> erList = new ArrayList<>();
Error er27 = new ErrorImpl("27",
"No detail found",
"Please enter detail.");
erList.add(er27);
Error er22 = new ErrorImpl("1",
"Maximum number exceeded",
"Please contact Technical Support.");
erList.add(er22);
for (int index = 0; index < erList.size(); index++) {
StringAttribute st = new StringAttributeImpl();
st.setName(erList.get(index).getDescription());
st.setValue(erList.get(index).getResolution());
errorMap.put(erList.get(index).getCode(), st);
}
List<Error> errorList = raterDao.findAllErrors();
assertThat(errorList, is(notNullValue()));
StringAttribute map27 = errorMap.get("27");
Mockito.when(rateService.findRwxlClientError("27")).thenReturn(map27);
StringAttribute map22 = errorMap.get("22");
Mockito.when(rateService.findRwxlClientError("22")).thenReturn(map22);
assertTrue("ParseShipment failed", map27.getName().equals("No detail found"));
assertTrue("ParseShipment failed", map22.getName().equals("Please contact Technical Support."));
}
}
My Main Class:
#Service
public class RateServiceImpl implements RateService {
protected final Log logger = LogFactory.getLog(getClass());
#Autowired
private RaterDao raterDao;
private Map<String, StringAttribute> errorMap = new HashMap<String, StringAttribute>();
#Resource
private MessageSource msg;
#PostConstruct
public void init() throws Exception {
**errorMap** = findAllClientErrors();
}
public Map<String, StringAttribute> findAllClientErrors() throws Exception {
List<Error> errorList = raterDao.findAllClientErrors();
for (int index = 0; index < errorList.size(); index++) {
StringAttribute st = new StringAttributeImpl();
st.setName(errorList.get(index).getDescription());
st.setValue(errorList.get(index).getResolution());
errorMap.put(errorList.get(index).getCode(), st);
}
return errorMap;
}
#Override
public StringAttribute findClientError(String code) throws Exception {
StringAttribute error = new StringAttributeImpl();
if (code.equals(Constants.ERROR_CODE_SETTING_UNAVAILABLE)) {
error.setName(msg.getMessage("SETTING.MESSAGE.ERROR", null,null));
error.setValue(msg.getMessage("SETTING.MESSAGE.RESOLUTION", null,null));
return error;
}
StringAttribute map = errorMap.get(code);
if (map == null || map.getName().isEmpty()) {
error.setName(msg.getMessage("DEFAULT.MESSAGE", new Object[] { code }, null));
error.setValue("");
} else {
error.setName(errorMap.get(code).getName());
error.setValue(errorMap.get(code).getValue());
}
return error;
}
}
I tried multiple solution but doesn't work, some time map becomes empty or null.
Any solution works which pass my test case.
I want to test findClientError(String code) and the issue is with errorMap
So, you can use ReflectionUtils.setField method. I made a small example, it is not exactly like your code, but overall you will get the idea.
So here's my class under test. Doing almost exactly like your example. I have hello method just to test and check if it is working or not.
class RateService {
private static Map<String, Object> errorMap = new HashMap<>();
#PostConstruct
public void init () {
this.errorMap = findAllErrors();
}
private Map<String, Object> findAllErrors() {
Map<String, Object> errorMap = new HashMap<>();
errorMap.put("a", new Object());
errorMap.put("b", new Object());
errorMap.put("c", new Object());
return errorMap;
}
// a method for demo purposes
public String hello() {
if (errorMap.size() > 0) {
return String.join(",", errorMap.keySet());
} else {
return "Empty";
}
}
}
Here's my test class. The third argument of the setField method is the object that is going to be set in that field. So, you can create a mock, or real object there. I assigned a real object with dummy values. Then tested against that.
class MainTest {
private RateService rateService;
#BeforeEach
void setUp() {
this.rateService = new RateService();
}
private Map<String, Object> exampleErrorObjects() {
Map<String, Object> errorMap = new HashMap<>();
errorMap.put("x", new Object());
errorMap.put("y", new Object());
errorMap.put("z", new Object());
return errorMap;
}
#Test
void testHello() {
// given:
ReflectionTestUtils.setField(RateService.class, "errorMap", exampleErrorObjects());
// when:
final String result = this.rateService.hello();
// then:
assertEquals("x,y,z", result);
}
}
I am setting the static field in a test method because you may want your class to be in different states (based on the errorMap field) in each test.

Mockito for SimpleJdbcCall with Spring JdbcTemplate

I tried multiple way to execute the store procedure in my Junit test case to test against the out values but unfortunately nothing is working.
My Test case:
public class DataTest {
#Mock
private static DataSource ds;
#InjectMocks
private DataDaoImpl dataDao = new DataDaoImpl();
#Mock
private static JdbcTemplate jdbcTemplate;
#Mock
private static SimpleJdbcCall viewProc;
#Before
public void setUp() throws IOException, InterruptedException {
MockitoAnnotations.initMocks(this);
MockMvcBuilders.standaloneSetup(dataDao).build();
}
#BeforeClass
public static void init() throws Exception {
viewProc = new SimpleJdbcCall(ds).withSchemaName("schema")
.withProcedureName("viewProc").withoutProcedureColumnMetaDataAccess()
.declareParameters(new SqlParameter("param1", Types.VARCHAR))
.declareParameters(new SqlParameter("param2", Types.VARCHAR))
.returningResultSet("dataModules", Mockito.anyObject());
jdbcTemplate = new JdbcTemplate(ds);
}
#Test
public void findDataModules() throws Exception {
String param1 = "abc";
List<DataObj> md = new ArrayList<DataObj>();
int size = 3;
SqlParameterSource in = new MapSqlParameterSource().addValue("param1", "abc").addValue("param2",
"123");
Map map = viewProc.execute(in);
md = (List<DataObj>) map.get("data");
assertTrue("Expected Data ", md.size() >= size);
}
}
My Main class:
#Repository
public class DataDaoImpl implements DataDao {
protected Logger logger = LoggerFactory.getLogger(getClass());
#Resource(name = "db")
private DataSource db;
private SimpleJdbcCall viewProc;
private JdbcTemplate jdbcTemplate;
/**
* Initialization of Stored Procs and JDBC Template
*
* #throws Exception
*/
#PostConstruct
public void init() throws Exception {
viewProc = new SimpleJdbcCall(db).withSchemaName("schema")
.withProcedureName("viewProc").withoutProcedureColumnMetaDataAccess()
.declareParameters(new SqlParameter("param1", Types.VARCHAR))
.declareParameters(new SqlParameter("param2", Types.VARCHAR))
.returningResultSet("data", new ViewDataRowMapper());
jdbcTemplate = new JdbcTemplate(db);
}
#Override
public List<Data> findUniqueDataModules(String p1, String p2) throws Exception {
List<DataObj> dataModules = new ArrayList<DataObj>();
try {
SqlParameterSource in = new MapSqlParameterSource().addValue("param1", p1).addValue("param2",
p2);
Map map = viewUniqueDataModulesByLicense.execute(in);
dataModules = (List<DataObj>) map.get("data");
} catch (Exception e) {
//Hnadel Exception
}
return dataModules;
}
}
Above code gives exception says datasource is required.
I tried Mockito, powerMockito but it returning empty map. There is no exceptions with mock.
I am OK with any solution which can pass my test case.
Modified naming.
As much as I hate using reflection in testing, I believe it can help you in your case. Here, after initializing, I set the field viewProc to a mock object which you can use in the test. #PostConstruct is a Spring related annotation, so it will not be called while initializing it.
class DataDaoImplTest {
private DataDaoImpl dataDao;
#Mock
private DataSource dataSource;
#Mock
private SimpleJdbcCall jdbcCall;
#BeforeEach
void setUp() {
MockitoAnnotations.initMocks(this);
this.dataDao = new DataDaoImpl(dataSource);
ReflectionTestUtils.setField(this.dataDao, "viewProc", jdbcCall);
}
#Test
void findUniqueDataModules() throws Exception {
// given:
Map<String, Object> map = new HashMap<>();
map.put("data", Arrays.asList(new DataDaoImpl.DataObj(), new DataDaoImpl.DataObj()));
// mocks:
when(jdbcCall.execute(any(SqlParameterSource.class))).thenReturn(map);
// when:
List<DataDaoImpl.DataObj> uniqueDataModules = this.dataDao.findUniqueDataModules("a", "b");
// then:
assertEquals(2, uniqueDataModules.size());
}
}
Another solution would be to test the method against a test database, like H2. But it won't be a unit test.

how to instantiate objects inside the class to be tested is an abstract class in Junit testing?

I have a class below for which I want to write a unit test
abstract class ProductImpl{
#Inject DataServices ds; // using Guice
public Response parse(String key, Long value){
Response res = ds.getResponseObject(); // Response object is created using DataServices object
res.id = key;
res.code = value;
}
}
And I have a test as below
class ProductImplTest{
#InjectMocks ProductImpl impl;
Map<String, Long> map;
#Before
map.put("abc", 10L);
map.put("xyz", 11L);
}
#Test
public void test(){
for(String key: map.keySet()){
Response res = impl.parse(key, map.get(key));
// and check if fields of Response object are set correctly i.e res.id is abc and value is 10L
}
}
But when i debug the test and control goes to parse method , DataServices object ds is null. How to instantiate this object through test . I do not want to use mocking, I want real response objects to be created and test the values set in them.
You can use Mockito
#RunWith(MockitoJUnitRunner.class)
class ProductImplTest {
#Mock DataService dService;
#InjectMocks ProductImpl sut;
#Test
public void test() {
ResponseObject ro = new ResponseObject();
String string = "string";
Long longVal = Long.valueOf(123);
sut.parse("string", longVal);
verify(dService).getResponseObject();
assertThat(ro.getId()).isEqualTo("string");
// you should use setters (ie setId()), then you can mock the ResponseObject and use
// verify(ro).setId("string");
}
}
EDIT:
With ResponseObject being an abstract class or preferably an interface, you'd have
interface ResponseObject {
void setId(String id);
String getId();
// same for code
}
and in your test
#Test public void test() {
ResponseObject ro = mock(ResponseObject.class);
// ... same as above, but
verify(dService).getResponseObject();
verify(ro).setId("string"); // no need to test getId for a mock
}
Try with constructor injection:
class ProductImpl{
DataServices ds;
#Inject
public ProductImpl(DataServices ds) {
this.ds = ds;
}
}

Junit for Controller class

I have controller method and for it I am making Junit but getting Null pointer error when it calling a service method. I used power mock but still getting Null pointer.
method:
#RequestMapping(method = RequestMethod.GET, value = "/DSR.do")
public ModelAndView displayDataSourceReportPage(HttpServletRequest request,Model model) {
log.debug(" Inside displayDataSourceReportPage method ");
Map<String, Object> map = new HashMap<String, Object>();
try {
request.setAttribute(MENU_SELECTED, LABEL_MENU_SOURCEDATA);
request.setAttribute(SUB_MENU_SELECTED, LABEL_SUBMENU_DSR);
#SuppressWarnings("rawtypes")
List dataSource = dataSourceReportService.listDataSourceReportByCurrentRunInd("C");
map.put("dataSource", dataSource);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return new ModelAndView("DataSourceReport", "model", map);
}
test Method:
#InjectMocks
private DataSourceReportController dataSourceReportController;
#Mock
private DataSourceReportService dataSourceReportServiceImpl;
#InjectMocks
private DataSourceReportDAO dataSourceReportDAO = new DataSourceReportDAOImpl();
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testdisplayDataSourceReportPage() throws Exception {
PowerMockito.mockStatic(DataSourceReport.class);
PowerMockito.mockStatic(HttpServletRequest.class);
PowerMockito.mockStatic(Model.class);
PowerMockito.mockStatic(DataSourceReportService.class);
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
Model model = Mockito.mock(Model.class);
dataSourceReportServiceImpl = PowerMockito.mock(DataSourceReportService.class);
DataSourceReport dataSourceReport = PowerMockito.mock(DataSourceReport.class);
dataSourceReport.setCurrentRunInd("abc");
dataSourceReport.setActualFileName("Somthing");
dataSourceReport.setFileCountId(3);
dataSourceReport.setFileId(4);
dataSourceReport.setRecCount(3);
List<DataSourceReport> list = new ArrayList<DataSourceReport>();
list.add(dataSourceReport);
String currentRunInd = "currentRunInd";
Object obj =getClass();
PowerMockito.when(dataSourceReportDAO.listDataSourceReportByCurrentRunInd(currentRunInd)).thenReturn(list);
DataSourceReportController ctrl = new DataSourceReportController();
ctrl.displayDataSourceReportPage(request, model);
}
getting Null at "dataSourceReportService.listDataSourceReportByCurrentRunInd("C");"
You need to have this in the test class
PowerMockito.when(dataSourceReportService.listDataSourceReportByCurrentRunInd("C")).thenReturn(list);
before calling
ctrl.displayDataSourceReportPage(request, model);
Thanks # Arthur Zagretdinov
I tried the below code and it worked.
private MockMvc mockMvc;
#Mock
private HttpServletRequest req;
#Mock
private DataSourceReportService dataSourceReportServiceImpl;
#InjectMocks
private DataSourceReportController controller;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
#Before
public void initMocks(){
MockitoAnnotations.initMocks(this);
}
#Test
public void testdisplayDataSourceReportPage() throws Exception {
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
Model model = Mockito.mock(Model.class);
DataSourceReport dataSourceReport =Mockito.mock(DataSourceReport.class);;
dataSourceReport.setCurrentRunInd("abc");
dataSourceReport.setActualFileName("Somthing");
dataSourceReport.setFileCountId(3);
dataSourceReport.setFileId(4);
dataSourceReport.setRecCount(3);
List<DataSourceReport> list = new ArrayList<DataSourceReport>();
list.add(dataSourceReport);
ModelAndView modelView = controller.displayDataSourceReportPage(request, model);
modelView.addObject(dataSourceReport);
}

How to write a junit test case for a method containing session map

I'm very new to Junit.
I'm writing junit for a interceptor.. It contains SessionMap in that.. while calling the interceptor from the test class I'm getting Null pointer exception at Session Map.
Below is my interceptor..
public String intercept(ActionInvocation actionInv) throws Exception {
ActionContext context = actionInv.getInvocationContext();
final HttpServletRequest request = (HttpServletRequest) context.get(ServletActionContext.HTTP_REQUEST);
String callerAppName = request.getParameter(CustomerPortalConstants.CALLER);
if(callerAppName == null){
//caller name is passed in header in case of OnePortal service request
callerAppName = request.getHeader(CustomerPortalConstants.CALLER);
}
SessionMap<String,Object> sessionMap = ((SessionMap<String,Object>)ActionContext.getContext().getSession());
#SuppressWarnings("unchecked")
Map<String,AccountBean> accountsMap = (Map<String,AccountBean>)sessionMap.get(CustomerPortalConstants.ACCOUNTSMAP);;
if(accountsMap == null) {
accountsMap = new HashMap<String, AccountBean>();
sessionMap.put(CustomerPortalConstants.ACCOUNTSMAP, accountsMap);
}
Im getting error at this location
((SessionMap)ActionContext.getContext().getSession());
This is my Test class..
public class MultiAccountInterceptorTest extends StrutsTestCase implements SessionAware {
/**
*
*/
private static final long serialVersionUID = 1L;
private Map<String,AccountBean> accountsMap=new HashMap<String, AccountBean>();
Map<String, Object> sessionMap;
private String callerAppName="LMP";
private final HttpServletRequest mockHttpReq = createMock(HttpServletRequest.class);
MultiAccountInterceptor interceptor = new MultiAccountInterceptor();
#SuppressWarnings("unchecked")
#Before
public void setUp() throws Exception {
sessionMap = new HashMap<String, Object>();
}
#SuppressWarnings("unchecked")
#Test
public void testIntercept() throws Exception
{
MultiAccountInterceptor mockInterceptor = PowerMock.createNicePartialMockForAllMethodsExcept(MultiAccountInterceptor.class, "intercept");
final ActionInvocation mockInvocation = createMock(ActionInvocation.class);
final ActionContext mockContext = createMock(ActionContext.class);
expect(mockInvocation.getInvocationContext()).andReturn(mockContext);
System.out.println(mockContext);
expect( (HttpServletRequest)mockContext.get(ServletActionContext.HTTP_REQUEST)).andReturn(mockHttpReq);
System.out.println(mockHttpReq);
expect(mockHttpReq.getParameter(CustomerPortalConstants.CALLER)).andReturn(callerAppName);
System.out.println("Caller app name is"+ callerAppName);
System.out.println(sessionMap);
sessionMap.put(CustomerPortalConstants.ACCOUNTSMAP, accountsMap);
System.out.println(sessionMap);
replayAll();
mockInterceptor.intercept(mockInvocation);
}
#Override
public void setSession(Map<String, Object> sessionMap) {
this.sessionMap=sessionMap;
}
}
Can anyone provide me a solution for this problem..
Thanks in advance..