In my spring based rest services I have a service method that returns a token, the method actaully consumes a Soap Service, I am not able to decide how to write a unit test for that. The method signature is below
public String methodName(){
String token="";
try {
token = util.getSoapService();
}catch(Exception e){
}
return token;
}
Can I use Junit and Mockito to test this code
You need to create a mock implementation of service, assign it to util variable and implement expected behaviour. After it check trat token value is correct.
Related
I am testing controller methods that include calls with:
SecurityUtils.getCurrentLoginId()
However, when I run this test
SecurityContext securityContext = Mockito.mock(SecurityContext.class);
Mockito.when(SecurityUtils.getCurrentLoginId()).thenReturn((long) 1);
SecurityContextHolder.setContext(securityContext);
RequestBuilder requestBuilder = MockMvcRequestBuilders
.post(uri)
.with(user("admin").password("pass").roles("USER","ADMIN"))
.with(csrf())
.param("blogId", "" + blogId)
.content(mapToJson(post))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON);
I get:
java.lang.IllegalStateException: User not found!
You are trying to mock static method, and Mockito doesn't support this feature. Please, use PowerMock instead.
You will find some examples of mocking static methods via PowerMock here.
I have a Spring MVC 4 app with Spring Security 4 and is deployed on Tomcat 8 running under jdk 1.8. The web-service has the controller defined as such:
#RequestMapping(value = "/build", method = RequestMethod.POST, produces = "application/json", headers =
{ "Accept=*/*", "Content-Type=*/*" })
public SubjectEntity build(#RequestBody SubjectImportDTO subjectImportDTO)
{
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
User user = null;
if (principal instanceof User)
{
user = ((User) principal);
}
SubjectEntity entity = service.build(subjectImportDTO);
System.out.println("FINISH: build");
return entity;
}
I am getting a csrf token, I have that setup correctly. I know the url is getting called correctly because I can see that in the logs when I get there. The service on the back-end is running, data is correctly entered into the database, I correctly get the write object, and using the Jackson Mapper, the object 'SubjectEntity' should be translated into JSON and sent back to the requesting client. This web-service has been unit tested under the Spring Web Test framework, and it works great!
So, I am familiar with an HTTP 404 error in not finding a URL when the wrong parameters are passed in, or you're trying to do a POST when it's a GET, etc. So many reasons why we can get a 404 error ...
BUT ... IN THIS CASE ... We've already gotten to the URL, executed the code, and then it has the data it needs. Since the Controller says we have content-type / and it produces application/json, I don't know what else could be wrong?
Any ideas?
You should add #ResponseBodyto your method. without this, Spring mvc tries to find another handler method which can send a response.
NB: #RestController automatically add #ResponseBody on each method in a controller.
I use Jersey and I have the following Rest function which returns a JSON string when my server is deployed:
#GET
#Path("getallemployees")
#Produces("application/json")
public Response getAllEmployees() {
//building the entity object which is List<Employee>
return Response.ok(entity).build();
}
I need to develop some unit tests (not integration testing) and I want to somehow mock the HTTPRequest that invokes this method and then get the json String. The best option would be to use mockito for this.
Is there any suggestion on how to do it ?
Thanks !!
The problem is that the method returns a Response object to the caller which is deep within the framework code. It doesn't return JSON strings.
You can use Mockito, if you need to mock something inside the method itself. That should work.
But you may need to take the value returned by the method and convert it to JSON like this if you are using Jackson with Jersey.
Response response = getAllEmployees();
Object retval = response.getEntity();
try {
ObjectMapper mapper = new ObjectMapper();
// I like this formatting. You can change it.
mapper.configure(Feature.INDENT_OUTPUT, true);
mapper.configure(Feature.WRITE_ENUMS_USING_TO_STRING, true);
mapper.configure(Feature.USE_ANNOTATIONS, false);
mapper.configure(Feature.FAIL_ON_EMPTY_BEANS, false);
mapper.setSerializationInclusion(Inclusion.NON_NULL);
mapper.getSerializationConfig().setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
mapper.getSerializationConfig().withSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
String json = mapper.writeValueAsString(retval);
... assert something about the string
} catch (JsonProcessingException e) {
// do something
} catch (IOException e) {
// do something
}
Some of this is guess work and speculation on my part but it may help. You could try using the Jersey Test Framework with the InMemoryTestContainerFactory:
It starts Jersey application and directly calls internal APIs to handle request created by client provided by test framework. There is no network communication involved. This containers does not support servlet and other container dependent features, but it is a perfect choice for simple unit tests.
It looks like to use it, all you need to do is extend JerseyTest and then override getTestContainerFactory() and follow the rest of the instructions, e.g.:
public class EmployeeResourceTest extends JerseyTest {
#Override
protected Application configure() {
// set up employee resource with mock dependencies etc...
return new ResourceConfig().registerInstances(employeeResource);
}
#Test
public void getAllEmployees() {
final String response = target("getallemployees").request().get(String.class);
// assert etc...
}
}
I used registerInstances instead of registerClasses in configure() as it looks like you can present a ready made Resource but set up with any mock dependencies you may want - although I haven't tried this myself.
The test class is a bit inflexible as you can only do one-time set up of dependencies in the configure() method, so it might be worth investigating using the MockitoJUnitRunner - although I'm not sure if it will work with the JerseyTest inheritance. It could allow you to do add behaviour to mocks in each #Test method, e.g.:
#Mock
private EmployeeResourceDependency dependency;
#InjectMocks
private EmployeeResource employeeResource;
// configure() as above but without mock setup up etc...
#Test
public void getAllEmployees() {
given(dependency.getEmployees()).willReturn(...);
// etc...
But like I said it might not be possible to mix them at all.
When we configure Spring AOP the JSON Results disappear for : AOPExression1
<aop:pointcut id="dmhMethodExecution"
expression="within(com.aditya.dmh..*)" />
So I added an exclusion for : AOPExpression1 as AOpExpression2
<aop:pointcut id="dmhMethodExecution"
expression="within(com.aditya.dmh..*)
and !within(com.aditya.dmh.controller..*)" />
in the ASPECTJ Expression
Still I donot see my JSON results from the controller which is a restful implementation.
package com.aditya.dmh.controller;
#Controller
public class EmployeeController {
private EmployeeServiceInterface employeeService;
#Autowired
public void setEmployeeService(EmployeeServiceInterface employeeService) {
this.employeeService = employeeService;
}
#RequestMapping("/employeeservices/1/allemployees.view")
public #ResponseBody Result<EmployeeModel> getEmployees(){
return employeeService.getEmployees(0, 10);
}
}
When I use log4j for the DEBUG messages I see the following:
15:37:04.214 [http-8090-1] DEBUG o.s.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'dmhServiceDispatcher': assuming HandlerAdapter completed request handling
15:37:04.214 [http-8090-1] DEBUG o.s.web.servlet.DispatcherServlet - Successfully completed request
When I remove the AOP the JSON results start to appear and I see that the additional Debug Message.
17:11:36.270 [http-8090-2] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Written [com.aditya.Result#8a85268] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#62ba2e48]
Looking at the Spring forums I understand that the Convertor is automatically configured when the
<mvc:annotation-driven/>
is used.
Is my problem of configuring AOP have anything to do with the RequestResponseBodymethodProcessor not being called.
Does this have anything to do with the proxies created around my controller when I use AOPExpression1. Why would an exclusion as in AOPExpression2 still have the problem.
Anyhelp would be appreciated
I belive that to intercept a request to a controller you should do it with MVC interceptors and not with aspects. What I did is to put into the applicationContext.xml this:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/employeeservices/1/allemployees.view"/>
<bean class="com.aditya.dmh.interceptor.ResultInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
Now, the class ResultInterceptor is where you put the code you want to be done, for instance:
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("--- preHandle --- ");
return true;
}
At least this is the way I did it.
Hope it helps.
This is a bit of a speculation:
I think what is happening is a CGLIB based dynamic proxy is getting created for your controller (although you have excluded it explicitly in your new pointcut expression), if this happens then #RequestMapping annotations are not correctly detected(by `) and so the controller is not there to handle your REST request.
Can you try a few things:
Have an interface for the controller with the exact same methods that the controller handles, and put the #RequestMapping annotations there, this will handle cases where the dynamic proxy is created and should work as expected even if the dynamic proxy gets created..
Play around a little more with your pointcut expression to see why a proxy for you controller may be getting created.
THE SOLUTION FOR OUR PROBLEM IN THIS CONTEXT
We found out that the whole thing was with the Around Advice in AOP Configuration that we have had.
Before Fix
public void logAround(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
joinPoint.proceed();
long totalTime = System.currentTimeMillis() - startTime;
log.debug(buildLogMessage(new StringBuilder().append(METHOD_AROUND_ID)
.append("[").append(totalTime).append("] ").toString(),
joinPoint));
return returnValue;
}
After Fix
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object returnValue = joinPoint.proceed();
long totalTime = System.currentTimeMillis() - startTime;
log.debug(buildLogMessage(new StringBuilder().append(METHOD_AROUND_ID)
.append("[").append(totalTime).append("] ").toString(),
joinPoint));
return returnValue;
}
the void effectively made sure that the Response Object sent by the logAround was not passed on back to the RequestResponseBodyMethodProcessor
Once we had it captured & returned the cglib proxies sent the response back to the processor & had the response sent back to the client.
Would appreciate any code examples of how to call a SpringWS endpoint intrceptor from a Junit test class. Particularly on how to prepare a SOAP message context and endpoint object. The SOAP message in the context will need to have a custom SOAP header included.
Something like....
public class MyInterceptorTest
private static String "... my XML SOAP test message ...";
#Test
public testMyInterceptor() {
myMessageContext = ... Build a MessageContext with the XML message string;
myEndPointObject = ... Build an endpoint object;
boolean result = MyInterceptorClass.handleRequest(myMessageContext, myEndPointObject);
... Check results;
}
Any examples would be appreciated.
The MessageContext can be created by instantiating a DefaultMessageContext object. The request WebServiceMessage can created using the test support class PayloadMessageCreator, but this only appeared in Spring-WS 2.x.
The endpoint object can be anything - it depends what your interceptor does with it. If it doesn't actually use it, then you can just pass in null.
I had the same issue and was able to figure it out in part using #skaffman's suggestion.
Basically, I had a custom EndpointInterceptor that I wanted to test with real data so that I would know I had everything correct.
You will have to upgrade spring-ws-test and other spring-ws dependencies to version 2.0 or higher. I ended up using something different than PayloadMessageCreator.
final Source payload = new StreamSource(new StringReader(soapPayload));
SaajSoapMessageFactory saajSoapMessageFactory = new SaajSoapMessageFactory(MessageFactory.newInstance());
WebServiceMessage requestPayload = new SoapEnvelopeMessageCreator(payload).createMessage(saajSoapMessageFactory);
MessageContext messageContext = new DefaultMessageContext(requestPayload, saajSoapMessageFactory);
soapPayload is the string value of an entire soap envelope.
Something similar to this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
...fill in your custom headers here
</soapenv:Header>
<soapenv:Body><someRequest>...</someRequest></soapenv:Body>
</soapenv:Envelope>
You will obviously need to fill in your request payload, any namespaces, as well as your custom headers.
I set the endpoint object to null as I was not doing anything with it as part of my interceptor.