Spring: Test JSP Output in JUnit Test - java

We have a API, which returns the JSP as the view, for example:
#RequestMapping(value = "/cricket/{matchId}", method = RequestMethod.GET)
public String getCricketWebView(HttpServletRequest request, #PathVariable("matchId") Integer matchId, ModelMap mv){
try{
return "webforms/cricket";
}catch(Exception e){
e.printStackTrace();
}
return "";
}
I wrote a unit test to test this out as follows:
#Test
public void test_cricket()
{
try {
MvcResult result =this.mockMvc.perform(get(BASE + "/cricket/123")
.accept(MediaType.TEXT_HTML))
.andExpect(status().isOk()).andReturn();
String json = result.getResponse().getContentAsString();
System.out.println(json);
} catch (Exception e) {
e.printStackTrace();
}
}
The problem is that, the unit tests only returns the string webforms/cricket and not the actual HTML from the cricket.jsp page. I understand this is happening because I am using the Mock MVC.
But, is there a way I can test the actual HTML? The reason is that we use some complex JSTL tags and we have seen in the past that unit test succeeds but the actual JSP page returns 500 error because of parsing failure.
I tried the following code:
try {
WebConversation conversation = new WebConversation();
GetMethodWebRequest request = new GetMethodWebRequest(
"http://localhost:8080/cricket/123");
WebResponse response = conversation.getResponse(request);
System.out.println(response.getResponseMessage());
}
catch (Exception e)
{
e.printStackTrace();
org.junit.Assert.fail("500 error");
}
But this gives, connection refused exception. Again I understand this is because web server is not setup at the time of test.
This is my configuration:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(locations = "file:src/main/webapp/WEB-INF/spring-resources/applicationcontext.xml")
public class MobileApiControllerTest {
...
}
I also tried using #WebIntegrationTest, but the same problem. It seems this only works for Spring boot application. Our application is a typical WAR application deployed on Tomcat.
Any idea how can I achieve the actual JSP output in unit test?

Reading and googling I think that this can't happen using the Spring Test framework. Spring test does not run the code(java code, jstl, i18n messages) inside the jsp! This is also a useful answer from so.
If you wish to test the jsp source, you have to use a client side test framework like Selenium or HttpUnit.

Related

JUnit Test: Unable to unmarshall element

I have encountered the following difficulty for close to a week now after trying countless solutions across the net. The specific problem relates to NullPointerException being thrown after calling the method Configuration.getUnmarshallerFactory().getUnmarshaller(Element) in my JUnit test.
The following is the dependency information for opensaml library imported into my project:
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml</artifactId>
<version>2.6.4</version>
</dependency>
The following is the implementation. During normal execution of the program/project, it is able to execute and return the Response object successfully.
private Response a(String text) throws ConfigurationException, SAXException {
DefaultBootstrap.bootstrap();
Schema s = SAMLSchemaBuilder.getSAML11Schema();
BasicParserPool bpp = new BasicParserPool();
bpp.setNamespaceAware(true);
bpp.setIgnoreElementContentWhitespace(true);
bpp.setSchema(schema);
InputStream is= new ByteArrayInputStream(Base64.decode(samlContent).getBytes());
Response res= null;
try {
Document doc = bpp.parse(is);
Element elmt= doc.getDocumentElement();
try {
QName qn = new QName(elmt.getNamespaceURI(), elmt.getLocalName(), elmt.getPrefix());
Unmarshaller um = Configuration.getUnmarshallerFactory().getUnmarshaller(qn); <== NullPointerException thrown at this line during JUnit Test**
samlResponse = (Response) unmarshaller.unmarshall(elmt);
} catch (XMLParserException e) {
logger.debug(e.getMessage());
} catch (UnmarshallingException e) {
logger.debug(e.getMessage());
}
return res;
}
The following is JUnit Test:
(I got a sample samlp:Response string from the following website: https://www.samltool.com/generic_sso_res.php)
#Test
public void test() throws Exception {
PowerMockito.mockStatic(DefaultBootstrap.class);
PowerMockito.doNothing().when(DefaultBootstrap.class, "bootstrap");
Response result = classInstance.a(Base64.encode(responseStringFromWebsite));
assertNotNull(result);
}
I would greatly appreciate any help or sharing of knowledge if any of you have encountered similar errors before.
By mocking method DefaultBootstrap # bootstrap, you've skiped initialization of required fields, I guess. Check up the source code of DefaultBootstrap.bootstrap(), it will clarify the reason of NPE.

Mocking/Testing HTTP Get Request

I'm trying to write unit tests for my program and use mock data. I'm a little confused on how to intercept an HTTP Get request to a URL.
My program calls a URL to our API and it is returned a simple XML file. I would like the test to instead of getting the XML file from the API online to receive a predetermined XML file from me so that I can compare the output to the expected output and determine if everything is working correctly.
I was pointed to Mockito and have been seeing many different examples such as this SO post, How to use mockito for testing a REST service? but it's not becoming clear to me how to set it all up and how to mock the data (i.e., return my own xml file whenever the call to the URL is made).
The only thing I can think of is having another program made that's running locally on Tomcat and in my test pass a special URL that calls the locally running program on Tomcat and then return the xml file that I want to test with. But that just seems like overkill and I don't think that would be acceptable. Could someone please point me in the right direction.
private static InputStream getContent(String uri) {
HttpURLConnection connection = null;
try {
URL url = new URL(uri);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "application/xml");
return connection.getInputStream();
} catch (MalformedURLException e) {
LOGGER.error("internal error", e);
} catch (IOException e) {
LOGGER.error("internal error", e);
} finally {
if (connection != null) {
connection.disconnect();
}
}
return null;
}
I am using Spring Boot and other parts of the Spring Framework if that helps.
Part of the problem is that you're not breaking things down into interfaces. You need to wrap getContent into an interface and provide a concrete class implementing the interface. This concrete class will then
need to be passed into any class that uses the original getContent. (This is essentially dependency inversion.) Your code will end up looking something like this.
public interface IUrlStreamSource {
InputStream getContent(String uri)
}
public class SimpleUrlStreamSource implements IUrlStreamSource {
protected final Logger LOGGER;
public SimpleUrlStreamSource(Logger LOGGER) {
this.LOGGER = LOGGER;
}
// pulled out to allow test classes to provide
// a version that returns mock objects
protected URL stringToUrl(String uri) throws MalformedURLException {
return new URL(uri);
}
public InputStream getContent(String uri) {
HttpURLConnection connection = null;
try {
Url url = stringToUrl(uri);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "application/xml");
return connection.getInputStream();
} catch (MalformedURLException e) {
LOGGER.error("internal error", e);
} catch (IOException e) {
LOGGER.error("internal error", e);
} finally {
if (connection != null) {
connection.disconnect();
}
}
return null;
}
}
Now code that was using the static getContent should go through a IUrlStreamSource instances getContent(). You then provide to the object that you want to test a mocked IUrlStreamSource rather than a SimpleUrlStreamSource.
If you want to test SimpleUrlStreamSource (but there's not much to test), then you can create a derived class that provides an implementation of stringToUrl that returns a mock (or throws an exception).
The other answers in here advise you to refactor your code to using a sort of provider which you can replace during your tests - which is the better approach.
If that isn't a possibility for whatever reason you can install a custom URLStreamHandlerFactory that intercepts the URLs you want to "mock" and falls back to the standard implementation for URLs that shouldn't be intercepted.
Note that this is irreversible, so you can't remove the InterceptingUrlStreamHandlerFactory once it's installed - the only way to get rid of it is to restart the JVM. You could implement a flag in it to disable it and return null for all lookups - which would produce the same results.
URLInterceptionDemo.java:
public class URLInterceptionDemo {
private static final String INTERCEPT_HOST = "dummy-host.com";
public static void main(String[] args) throws IOException {
// Install our own stream handler factory
URL.setURLStreamHandlerFactory(new InterceptingUrlStreamHandlerFactory());
// Fetch an intercepted URL
printUrlContents(new URL("http://dummy-host.com/message.txt"));
// Fetch another URL that shouldn't be intercepted
printUrlContents(new URL("http://httpbin.org/user-agent"));
}
private static void printUrlContents(URL url) throws IOException {
try(InputStream stream = url.openStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) {
String line;
while((line = reader.readLine()) != null) {
System.out.println(line);
}
}
}
private static class InterceptingUrlStreamHandlerFactory implements URLStreamHandlerFactory {
#Override
public URLStreamHandler createURLStreamHandler(final String protocol) {
if("http".equalsIgnoreCase(protocol)) {
// Intercept HTTP requests
return new InterceptingHttpUrlStreamHandler();
}
return null;
}
}
private static class InterceptingHttpUrlStreamHandler extends URLStreamHandler {
#Override
protected URLConnection openConnection(final URL u) throws IOException {
if(INTERCEPT_HOST.equals(u.getHost())) {
// This URL should be intercepted, return the file from the classpath
return URLInterceptionDemo.class.getResource(u.getHost() + "/" + u.getPath()).openConnection();
}
// Fall back to the default handler, by passing the default handler here we won't end up
// in the factory again - which would trigger infinite recursion
return new URL(null, u.toString(), new sun.net.www.protocol.http.Handler()).openConnection();
}
}
}
dummy-host.com/message.txt:
Hello World!
When run, this app will output:
Hello World!
{
"user-agent": "Java/1.8.0_45"
}
It's pretty easy to change the criteria of how you decide which URLs to intercept and what you return instead.
The answer depends on what you are testing.
If you need to test the processing of the InputStream
If getContent() is called by some code that processes the data returned by the InputStream, and you want to test how the processing code handles specific sets of input, then you need to create a seam to enable testing. I would simply move getContent() into a new class, and inject that class into the class that does the processing:
public interface ContentSource {
InputStream getContent(String uri);
}
You could create a HttpContentSource that uses URL.openConnection() (or, better yet, the Apache HttpClientcode).
Then you would inject the ContentSource into the processor:
public class Processor {
private final ContentSource contentSource;
#Inject
public Processor(ContentSource contentSource) {
this.contentSource = contentSource;
}
...
}
The code in Processor could be tested with a mock ContentSource.
If you need to test the fetching of the content
If you want to make sure that getContent() works, you could create a test that starts a lightweight in-memory HTTP server that serves the expected content, and have getContent() talk to that server. That does seem overkill.
If you need to test a large subset of the system with fake data
If you want to make sure things work end to end, write an end to end system test. Since you indicated you use Spring, you can use Spring to wire together parts of the system (or to wire the entire system, but with different properties). You have two choices
Have the system test start a local HTTP server, and when you have your test create your system, configure it to talk to that server. See the answers to this question for ways to start the HTTP server.
Configure spring to use a fake implementation of ContentSource. This gets you slightly less confidence that everything works end-to-end, but it will be faster and less flaky.

RequestDispatcher.include is working only once

I am trying to output the rendering of a JSP page using RequestDispatcher.include() in the following method:
public static String readTemplate(HttpServletRequest request, HttpServletResponse response, String template) {
HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper(response) {
private final StringWriter sw = new StringWriter();
#Override
public PrintWriter getWriter() throws IOException {
return new PrintWriter(sw);
}
#Override
public String toString() {
return sw.toString();
}
};
String templateFile = "/templates/" + template + ".jsp";
logger.log(Level.INFO, "Reading template {0} ...", templateFile);
try {
request.getRequestDispatcher(templateFile).include(request, responseWrapper);
} catch (ServletException | IOException | IllegalStateException e) {
logger.log(Level.SEVERE, e.getMessage());
}
logger.log(Level.INFO, "Completed reading template {0}", templateFile);
// retrieve HTML from response
return responseWrapper.toString();
}
The method is part of a servlet I am running with Tomcat8. This works perfectly the first time, but hangs at the include call the second run (i.e. if I click refresh on the browser).
I have already verified the dispatcher is not null.
This is what I can see from the catalina.log (cleaned for your review)
First run:
26-Feb-2015 17:41:17.921 INFO [http-nio-8081-exec-2] ism.Reports.readTemplate Reading template /templates/INCIDENT_REPORT.jsp ...
26-Feb-2015 17:41:18.046 INFO [http-nio-8081-exec-2] ism.Reports.readTemplate Completed reading template /templates/INCIDENT_REPORT.jsp
Second run (response never returns, i.e. browser always loading page):
26-Feb-2015 17:41:26.327 INFO [http-nio-8081-exec-8] ism.Reports.readTemplate Reading template /templates/INCIDENT_REPORT.jsp ...
This does not change until I reboot Tomcat.
Can someone explain what am I doing wrong or at least how to debug this? Thanks!
EDIT 1: Forgot to say the method is static, but I also tried making it not static didn't make any difference
The code above is working, I realized where the issue was. The included JSP page was opening many MySQL connections but only one was closed. Hence the second request was waiting for the MYSQL resources to be freed before performing the task. I am very sorry I didn't notice this until now, and I didn't even mention MySQL connections in the first place. I guess not receiving replies here lead me to find the solution on the JSP file itself.

Can REST-API controller packaged in JAR be called?

I have packaged and deployed my TestRestController.java(PFB code) in a JAR(testrest.jar) in an EAR in JBOSS EAP-6.2,
How can I access my REST-API, i tried hitting the http://{WEB-SERVER-IP}:8080/testrest/test/execute URL from a REST client? But I get HTTP 404.
Is it even possible?
TestRestController.java:
#Path("/test")
public class TestRestController
{
#POST
#Path("/execute")
#Consumes(MediaType.APPLICATION_JSON)
public Response executeRestApi(TestControllerDTO testControllerDto)
{
try
{
if (validateRequestParams(testControllerDto))
{
System.out.println("Validation success.");
response = Response.status(Status.OK).entity("Validation success.").build();
}
else
{
System.out.println("Validation failed.");
response = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Validation failed.").build();
}
}
catch (Exception e)
{
response = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Validation failed.").build();
}
return response;
}
private boolean validateRequestParams(TestControllerDTO testControllerDto)
{
boolean areParamsValid = false;
if (null != testControllerDto)
{
areParamsValid = true;
}
return areParamsValid;
}
}
Please help me.
P.S. : I am a newbie to Java and REST.
Thanks in advance.
You need to initiate the rest servlet somehow. The easiest way is to just add an javax.ws.rs.core.Application with an #ApplicationPath annotation to your application.
#ApplicationPath("/rest")
public class JaxRSApplication extends Application {
}
It can be left empty. It can packaged either in your .jar or in the .war (keep in mind, the .jar should also be included in the war in the WEB-INF/lib). With this the rest servlet will get initialized automatically and the classpath will be scanned for your resource classes annotated with #Path
You can see other deployment options here and for more detailed information, you can see the spec.
With the above Application class, you should be able to access
http://localhost:8080/my-app/rest/test/execute

How to use SOAP web service in User Interface?

I am doing web service now, and already succeed installing SOAP in my web service..
It is working perfectly when i "run as java application".. (I use eclipse as my environment)
Here is my client method:
public static void main(String[] args) {
LogbookSOAPServiceLocator locator = new LogbookSOAPServiceLocator();
try {
LogbookSOAP logbookSOAP = locator.getLogbookSOAPPort();
System.out.println(logbookSOAP.fetchLog("21").getDriverName());
} catch (ServiceException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}
This succesfully work in console, can i use it anywhre in my user interface? like .jsp file?
Thanks!
Sure you can. At first you need to install web container to deploy your application. Then create web project. Step by step tutorial by Oracle based on Oracle WebLogic Server but you can use other one.
The simpliest way to using JSP Scriptlets and put all our logic in JSP page.
<%#page import="your imports here"%>
........
<%
LogbookSOAPServiceLocator locator = new LogbookSOAPServiceLocator();
try {
LogbookSOAP logbookSOAP = locator.getLogbookSOAPPort();
System.out.println(logbookSOAP.fetchLog("21").getDriverName());
} catch (ServiceException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
%>
But it is not really good way because as your know best practice is to avod code logic in JSP pages especially Scriptets JSP coding conventions. Better code it in java wrapper class which you can call from JSP and after executing it will return result to the page.

Categories