How to create an instance of HttpServletRequest for unit testing? - unit-testing

While doing some searches on SO I came across this piece of code to extract the "appUrl" from a URL:
public static String getAppUrl(HttpServletRequest request)
{
String requestURL = request.getRequestURL().toString();
String servletPath = request.getServletPath();
return requestURL.substring(0, requestURL.indexOf(servletPath));
}
My question is how does one unit test something like this? The key problem is how to create an instance of HttpServletRequest for unit testing?
Fwiw I tried some googling and most of the responses center around mocking the class. But if I mock the class so that getRequestURL returns what I want it to return (taking an example since mocking essentially overrides some methods to return canned values), then I am not really testing the code at that point. I also tried the httpunit library but that also does not help.

I use mockito and here is the block of code in the test method I use to mock it up:
public class TestLogin {
#Test
public void testGetMethod() throws IOException {
// Mock up HttpSession and insert it into mocked up HttpServletRequest
HttpSession session = mock(HttpSession.class);
given(session.getId()).willReturn("sessionid");
// Mock up HttpServletRequest
HttpServletRequest request = mock(HttpServletRequest.class);
given(request.getSession()).willReturn(session);
given(request.getSession(true)).willReturn(session);
HashMap<String,String[]> params = new HashMap<>();
given(request.getParameterMap()).willReturn(params);
// Mock up HttpServletResponse
HttpServletResponse response = mock(HttpServletResponse.class);
PrintWriter writer = mock(PrintWriter.class);
given(response.getWriter()).willReturn(writer);
.....
Hope that helps, I use this to test methods that require servlet objects to work.

Related

Spock stubbing RestTemplate works when breakpoint is added

I am writing an unit test in Spock and trying to stub RestTemplate.postForEntity() but seeing a weird issue where the stubs only works when I add a breakpoint and evaluate the expression. It doesnt work and calls the postForEntity() method when run normally.
Here is my implementation.
Test:
def "AuthTokenRequest"() {
given:
def url = "https://authEndpoint"
def map = new LinkedMultiValueMap<>()
RestTemplate restTemplate = GroovySpy(global: true)
restTemplate.postForEntity(*_) >> new ResponseEntity(new AuthResponse(), HttpStatus.OK)
when:
def responseEntity = client.authTokenRequest(url, map)
then:
responseEntity == response
}
Method making the HTTP request:
public AuthResponse authTokenRequest(String url, MultiValueMap map) {
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<AuthResponse> responseEntity = restTemplate.postForEntity(url, createAuthEntity(map), AuthResponse.class);
return responseEntity.getBody()?:null
}
When I run this test, I get a java.net.UnknownHostException exception because https://authEndpoint doesnt point anywhere which also proves that postEntity() is not being stubbed.
When I put a breakpoint on ResponseEntity<AuthResponse> responseEntity = restTemplate.postForEntity(url, createAuthEntity(map), AuthResponse.class); and evaluate the expression, I get the stubbed response.
Am I doing this wrong?

Spring boot Unit test with #WebMvcTest - execution doesn't enter service layer from controller and returns null without error

I am writing unit test for a controller of my spring boot application.
I have typical MVC classes: ObjectSchemaController, ObjectSchemaService and ObjectSchemaDao.
I have written unit test with #WebMvcTest and mocked my service and dao class with #MockBean. (following this guide: https://www.baeldung.com/spring-boot-testing)
Below is my unit test :
#RunWith(SpringRunner.class)
#WebMvcTest(ObjectSchemaController.class)
public class ObjectSchemaControllerTest2 {
#Autowired
private MockMvc mvc;
#MockBean
private ObjectSchemaService service;
#MockBean
private ObjectSchemaDao dao;
#Autowired
ObjectMapper objectMapper;
#Test
public void testCreateObjectSchemaPass() throws Exception {
String payload = "{\"some_key\":\"some val\"}";
ObjectSchema objectSchema = objectMapper.readValue(payload, ObjectSchema.class);
Mockito.when(service.createSchema(objectSchema))
.thenReturn(objectSchema);
Mockito.when(dao.createSchema(objectSchema)).thenReturn(objectSchema);
mvc.perform(MockMvcRequestBuilders.post("/objectservice/schema/")
.contentType("application/json")
.content(objectMapper.writeValueAsString(objectSchema)))
.andExpect(status().isOk());
}
}
below is my service class:
#Service
public class ObjectSchemaService {
#Autowired
ObjectSchemaDao objectSchemaDao;
public ObjectSchema createSchema(#Valid ObjectSchema objectSchema)throws Exception {
return objectSchemaDao.createSchema(objectSchema);
}
}
The issue I am facing with Unit test is, the service layer doesn't get executed and returns null value.
When I debug, I can see execution reaching in my controller class and ObjectSchemaService as being mockito-mocked in the controller. But the execution never goes in service layer and the value returned by service method is null.
I have referenced other guides- they are doing similar steps. But its not working for me. What am I missing here?
I have also seen this post with similar issue.
Unit Test POST with #WebMvcTest - #MockBean Service returns null
I made sure the input objects to both my actual controller and the one I am passing in unit case are instances of same class.
You are mocking the ObjectSchemaService but no behaviour is expected.
You need to setup the behaviour for the services that are mocked. So depending on the method signature and result somethink like.
Mockito.when(service.createSchema(Mockito.any(ObjectSchema.class)).thenReturn(objectSchema);
At the moment the ObjectSchemaService mock just returns a default value which is null in your case.
In order to be transparent and unobtrusive all Mockito mocks by default return 'nice' values. For example: zeros, falseys, empty collections or nulls.
If you update your answer with details for ObjectSchemaService I could also update my answer.
You mock ObjectSchemaService so you need to tell the service how mock the values from the service when a method is called. If you don't mock the values of the service Mockito don't know what they have to return always give you null. Not need to mock ObjectSchemaDao in this test.
Note: I use Lombok in the code as ObjectSchema.builder() to return the object with the Id when is stored in the database, you can use a constructor. Assuming the service return the object.
The code looks like this:
import static org.mockito.BDDMockito.given;
#Test
public void testCreateObjectSchemaPass() throws Exception {
String payload = "{\"some_key\":\"some val\"}";
ObjectSchema objectSchema = objectMapper.readValue(payload, ObjectSchema.class);
given(service.createSchema(objectSchema)).willReturn(
ObjectSchema.builder()
.id(1)
.someKey("Some Val")
.build());
mvc.perform(MockMvcRequestBuilders.post("/objectservice/schema/").contentType("application/json").content(objectMapper.writeValueAsString(objectSchema)))
.andExpect(status().isOk());
}

how to mock different responses for a method with different parameters in Mockito

I am using Mockito to mock my external service and my method that dealing with the external service look like:
public class ExternalConnector{
public ResponseRaw callExternal(RequestParams request, ResponseRaw responseType){
...my implementation to call external service...
}
}
and I mock my response as follow:
ExternalConnector externalConnector = Mockito.spy(new ExternalConnector());
ResonseRaw myMockResponse = ..... mock the response
RequestParams myParameter = ..... mock the params
doReturn(myMockResponse)//
.when(externalConnector)//
.callExternal(isA(myParameter.getClass()), isA(MyResponse.class));
Till now it worked fine. But if I make another mock for my callExternal method with another RequestParams object, then it will get confused here and does not know which response it should mock, something like :
ResonseRaw myMockResponse = ..... mock the response
RequestParams myParameter = ..... mock the params
doReturn(myMockResponse)//
.when(externalConnector)//
.callExternal(isA(myParameter.getClass()), isA(MyResponse.class));
ResonseRaw myMockResponse2 = ..... mock the response
RequestParams myParameter2 = ..... mock the params
doReturn(myMockResponse2)//
.when(externalConnector)//
.callExternal(isA(myParameter2.getClass()), isA(MyResponse.class));
The problem is that myParameter.getClass() and myParameter2.getClass() both return the same RequestParams class type, and therefore basically the signiture for the mock is the same for both cases.
I tried to change the signiture for my mock from isA to eq, but it still did not work:
doReturn(myMockResponse2)//
.when(externalConnector)//
.callExternal(eq(myParameter), isA(MyResponse.class));
Can anyone help me at this point here? Thank you

JMS Testing - JMSTemplate send not executed

I have code piece sending jms messages via Spring JMSTemplate. For testing the the method i use Mockito.
My code looks like following.... publishDialogueServiceMessage()->
brokerUrl = jmsQueueProperties.getProperty(MessageRouterConstants.JMS_QUEUE_URL);
LOG.info("The broker url is : {}", brokerUrl);
jmsTemplate.send(jmsQueueProperties.getProperty(MessageRouterConstants.QUEUE), new MessageCreator() {
#Override
public Message createMessage(Session session) throws JMSException {
ObjectMessage obj = session.createObjectMessage(serviceResponse);
messageSent = true;
return obj;
}
});
In above code to i set boolean variable true, to check that if the message is sent
My Test looks following,
#Before
public void setUp() throws Exception {
connectionFactory = Mockito.spy(new ActiveMQConnectionFactory(
"vm://localhost?broker.persistent=false"));
conn = connectionFactory.createConnection();
conn.start();
}
#After
public void cleanUp() throws Exception{
conn.stop();
}
#Test
public void testPublishDialogueServiceMessage()
{
ServiceResponse response = Mockito.mock(
ServiceResponse.class, Mockito.withSettings()
.serializable());
JmsTemplate mockTemplate = Mockito.mock(JmsTemplate.class);
java.util.Properties p = Mockito.mock(java.util.Properties.class);
Mockito.when(p.getProperty(MessageRouterConstants.QUEUE))
.thenReturn("outbound.request.queue");
mockTemplate.setConnectionFactory(connectionFactory);
mockTemplate.setDeliveryPersistent(true);
mockTemplate.setSessionAcknowledgeMode(2);
mockTemplate.setSessionTransacted(true);
ReflectionTestUtils.setField(publisher, "jmsQueueProperties", p);
ReflectionTestUtils.setField(publisher, "jmsTemplate", mockTemplate);
// test
publisher.publishDialogueServiceMessage(response);
ArgumentCaptor<MessageCreator> msgCreator = ArgumentCaptor.forClass(MessageCreator.class);
Mockito.verify(p, Mockito.times(2))
.getProperty(Mockito.anyString());
Mockito.verify(mockTemplate, Mockito.times(1)).send(
Mockito.anyString(), Mockito.any(MessageCreator.class));
//MessageCreator msgCrt = Mockito.spy(msgCreator.getValue());
//Assert.notNull(msgCrt);
Assert.isTrue(publisher.isMessageSent());
}
In test i facing an interesting problem as publisher.isMessageSent() always returns me FALSE indicating that send message seems not executed(?). but Mockito.verify(mockTemplate, Mockito.times(1)).send(Mockito.anyString(), Mockito.any(MessageCreator.class)); goes fine.
I am wondering what is the cause that my messageSent variable not setting. Can anyone shed some light what I might be doing wrong.
Simple, you have a mock for the jmsTemplate (your mockTemplate). When a method is invoked on a mock it doesn't do anything other than record the call to the mock. So the mock doesn't know that it should attempt to invoke the msgCreator.
Looking at your test I see some obvious issues that suggest a lack of knowledge of Mockito. Why are you setting all of those fields on mockTemplate? It is a mock, it will not use those fields anyway. This also suggests that you don't need the code in your #Before and #After.
If you REALLY want your test to send a message via JMS (and thereby invoke the message createor) you should use a spy on JmsTemplate instead of a mock. However, I would highly discourage this as your test will be dependent on an external system and you would in effect be testing JsmTemplate. The fact that your mock gets invoked properly is sufficient. The only additional thing I think you need to do is to invoke the message creator being passed to the mock to verify that it creates the message correctly.

JUnit Testing FacesContext.getExternalContext

I have the following code in a Java EE managed bean:
FacesContext context = facesContextProvider.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) context.getExternalContext();
Where facesContextProvider is a custom class for returning the faces context (useful for mock testing).
I'm wondering how to test this in JUnit using mockito. I am trying a combination of:
FacesContextProvider mockFacesContextProvider = mock(FacesContextProvider.class);
when(mockFacesContextProvider.getCurrentInstance()).thenReturn(mockFacesContext);
// this line is wrong ~> when(mockFacesContext.getExternalContext()).thenReturn((ExternalContext) new MockHttpServletResponse());
How can I inject some sort of mock or custom HttpServletResponse into my external context?
Thanks for the help.
ANSWER
My controller code is wrong. You can work with the ExternalContext to do whatever you need. So in the controller, it should actually be:
FacesContext facesContext = facesContextProvider.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
externalContext.responseReset();
If you still wanted the response, you could get it from:
HttpResponse response = externalContext.getResponse();
Then the unit test harness would be:
mockFacesContextProvider = mock(FacesContextProvider.class);
mockFacesContext = mock(FacesContext.class);
mockExternalContext = mock(ExternalContext.class);
mockHttpSession = mock(HttpSession.class);
when(mockFacesContextProvider.getCurrentInstance()).thenReturn(mockFacesContext);
when(mockFacesContext.getExternalContext()).thenReturn(mockExternalContext);
when(mockExternalContext.getSession(true)).thenReturn(mockHttpSession);
And then the Unit Test code would be:
verify(mockExternalContext).responseReset();
FacesContextProvider mockFacesContextProvider = mock(FacesContextProvider.class);
HttpServletResponse mockResponse = mock(HttpServletResponse.class);
when(mockFacesContextProvider.getCurrentInstance()).thenReturn(mockFacesContext);
when(mockFacesContext.getExternalContext()).thenReturn(mockResponse);