Unable to run Mockito junit test - junit

I am very new to JUnit. I wrote a simple JUnit test case which gives NullPointerException:
#RunWith(MockitoJUnitRunner.class)
public class ControllerTest {
#InjectMocks
Controller control;
#Mock
Service service;
#Test
public void postTest() throws IOException {
//Given
Object o = new Object();
//initialise the object here which the service layer would return
String a = "abcd";
Integer b = 5;
Mockito.when(service.Post(a,o)).thenReturn(o);
Mono<ResponseEntity<Object>> object = control.Post(a,o);
StepVerifier.create(object)
.consumeNextWith(entity -> {
assertEquals(b,entity.getBody().get());
})
.expectComplete();
I get a NullPointerException for this scenario.

Related

Mock not initiated on Static method

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

mocking an autowired object and calling a method from that object

I have a class like this shown below:
public class Service {
#Value("${value1"})
String val1;
#Value("${value2"})
String val2;
#Value("${value1"})
String val3;
#Autowired
Client obj;
public String getResponse(String location, WebRequest request) {
// getting invocation target exception
String id = (String)request.getAttribute(Globals.id, request.SCOPE_REQUEST);
Point p = obj.getPoint(new Id(val1, val2, val3), "some string");
// do something
return getReply(id);
}
}
My test class is shown below:
public class ServiceTest {
#Mock
WebRequest request;
#Mock
Service service;
#Mock
Client obj;
#Before
public void setup() throws Exception {
}
#Test
public void testGetResponse() throws Exception {
when(request.getAttribute(Matchers.anyString(), Matchers.anyInt()).thenReturn("shbchdbchd");
when(obj.getPoint(Id.valueOf("id"), "some string").thenReturn("shbchdbchd");
service.getResponse("some location",request);
}
But the when(obj.getPoint) is not working, the parameters are null in the actual call in the class Service. This line
obj.getPoint(new Id(val1, val2, val3), "some string");
is getting null parameters.
It seems like you're using Spring in your Service class and no Spring in your unit test. As you're at the moment mocking all member variables in the class ServiceTest the unit test doesn't really test anything from the Service class.
A solution would be to manually setup your service instance in the unit test.
public class Service {
//....
#Autowired
public Service (
#Value("${value1"}) String value1,
#Value("${value2"}) String value2,
#Value("${value3"}) String value3,
Client client
){
this.val1=value1;
this.val2=value2;
this.val3=value3;
this.obj=client;
}
//....
public String getResponse(String location, WebRequest request) {
// getting invocation target exception
String id = (String)request.getAttribute(Globals.id, request.SCOPE_REQUEST);
//should you pass id instead of val1,val2,val3?
Point p = obj.getPoint(new Id(val1, val2, val3), "some string");
// do something
return getReply(id);
}
}
public class ServiceTest {
#Mock
WebRequest request;
#Mock
Client obj;
Service service;
#Before
public void setup() throws Exception {
service = new Service("value1","value2","value3",obj);
}
#Test
public void testGetResponse() throws Exception {
when(request.getAttribute(Matchers.anyString(), Matchers.anyInt()).thenReturn("shbchdbchd");
when(obj.getPoint(Id.valueOf("value1","value2","value3"), "some string").thenReturn("shbchdbchd");
service.getResponse("some location",request);
}
but to me it's still unclear what you really want to test.

Spring Integration - How to mock input-channel

I am new to Spring Integration so please forgive and correct me if my question is absurd. I am trying to write Unit test cases for Spring Integration application where I am testing only controller and looking to mock service call.
Test:
#RunWith(PowerMockRunner.class)
#PrepareForTest({HeaderUtils.class})
#PowerMockIgnore({ "javax.management.*", "javax.script.*" })
public class DocMgmtImplTestPower {
private MockMvc mvc;
#InjectMocks
private DocMgmtImpl docMgmtImpl;
#Mock
DocMgmtService docMgmtServiceGateway;
#Mock
SendComnMsgResponse sendComnMsgResponse;
#Before
public void init() {
MockitoAnnotations.initMocks(this); //
mvc = MockMvcBuilders.standaloneSetup(DocMgmtImpl.class).build();
PowerMockito.mockStatic(HeaderUtils.class, new Answer<Map<String, Object>>() {
#Override
public Map<String, Object> answer(InvocationOnMock arg0) throws Throwable {
Map<String, Object> headers = new HashMap<String, Object>();
HeaderInfo headerInfo = new HeaderInfo();
headers.put(BusinessServiceConstants.SERVICE_HEADER, headerInfo);
return headers;
}
});
}
#SuppressWarnings("deprecation")
#Test
public void testMethod() throws Exception {
SpecialFormMsgRequest arg = new SpecialFormMsgRequest();
Map<String, Object> headers = new HashMap<String, Object>();
Mockito.when(docMgmtServiceGateway.specialFormMsg(Mockito.any(SpecialFormMsgRequest.class),
(Matchers.<Map<String, Object>>any()))).thenReturn(new SendComnMsgResponse());
SpecialFormMsgRequest msg = new SpecialFormMsgRequest();
msg.setUiStaticDocFlag("N");
mvc.perform(post("/specialMsg").accept(MediaType.APPLICATION_JSON).content(asJsonString(msg))
.contentType(MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().isOk());
}
public static String asJsonString(final Object obj) {
try {
return new ObjectMapper().writeValueAsString(obj);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Controller:
#Controller
public class DocMgmtImpl implements DocMgmt {
#Autowired
**DocMgmtService docMgmtServiceGateway;** **// I want to mock this service.**
#Override
#RequestMapping(value = "/specialMsg", method = RequestMethod.POST)
#ResponseBody
public SendComnMsgResponse specialMsg(#Valid #RequestBody final SpecialFormMsgRequest specialFormMsgRequest)
throws BusinessException, TechnicalException {
SendComnMsgResponse sendComnMsgResponse = null;
try {
Map<String, Object> headers = HeaderUtils.getHeaders(poBusinessHeader); // PowerMockito working here...
sendComnMsgResponse = **this.docMgmtServiceGateway.specialFormMsg(specialFormMsgRequest, headers);** // docMgmtServiceGateway is getting null...
} catch (Exception exception) {
handleException(exception);
}
return sendComnMsgResponse;
}
}
Gateway.xml:
<int:gateway id="docMgmtServiceGateway" service-interface="group.doc.svc.gateway.DocMgmtService"
default-reply-channel="docReplyChannel" error-channel="docErrorChannel">
<int:method name="sendComnMsg" request-channel="sendComnMsgRequestChannel" />
</int:gateway>
si-chain.xml:
<int:chain input-channel="esDBBISendComnMsgRequestChannel" output-channel="docReplyChannel">
<int:transformer method="formatRequest" ref="esSendComnMsgTransformer"/>
<int:service-activator ref="sendComnMsgActivator" method="sendComnMsg" />
<int:transformer method="parseResponse" ref="esSendComnMsgTransformer"/>
</int:chain>
I am wondering, whether I am doing correct or not. Because DocMgmtService service is an interface and it don't have implementation. After controller call goes to Transformer as configured above. On this setup I have following quetions.
Can I mock DocMgmtService service with same setup if not what will be correct approach.
If yes then how can I mock my service.
Thanks
It depends on exactly what you want to test.
If you mock the interface, all you are testing is your mock stubbing for that interface (pointless).
The framework creates an implementation of the interface which creates a message from the parameters and sends it to the channel.
You should auto wire the gateway into your test and call it.
You can mock any of the downstream components (e.g. sendComnMsgActivator) as needed.

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;
}
}