Jetty's ServletTester is pretty useful for testing Servlet apps. I have used Jetty 6's ServletTester before and it worked perfectly.
For example:
Jetty 6.x
pom.xml
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-servlet-tester</artifactId>
<version>6.1.26</version>
<scope>test</scope>
</dependency>
SampleServletTest.java
package example;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.mortbay.jetty.testing.HttpTester;
import org.mortbay.jetty.testing.ServletTester;
public class SampleServletTest {
#Test
public void testDoGet() throws Exception {
ServletTester tester = new ServletTester();
tester.addServlet(SampleServlet.class, "/index");
tester.start();
HttpTester request = new HttpTester();
request.setMethod("GET");
request.setHeader("Host", "tester"); // should be "tester"
request.setURI("/index");
request.setVersion("HTTP/1.1");
request.setContent("");
String responses = tester.getResponses(request.generate());
HttpTester response = new HttpTester();
response.parse(responses);
assertThat(response.getStatus(), is(equalTo(200)));
}
}
Jetty 9.x
ServletTester's APIs are much improved in Jetty 9.x.
pom.xml
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>9.0.7.v20131107</version>
<scope>test</scope>
</dependency>
SampleServletTest.java
package example;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.servlet.ServletTester;
public class SampleServletTest {
#Test
public void testDoGet() throws Exception {
ServletTester tester = new ServletTester();
tester.addServlet(SampleServlet.class, "/index");
tester.start();
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setHeader("Host", "tester"); // should be "tester"
request.setURI("/index");
request.setVersion("HTTP/1.1");
request.setContent("");
HttpTester.Response response = HttpTester.parseResponse(tester.getResponses(request.generate()));
assertThat(response.getStatus(), is(equalTo(200)));
}
}
New API looks very cool but unfortunately above code runs much slowly... This code takes 10 seconds to run every time. Can you believe it?
Is there anyone who has knowledge of this issue? If this is just my mistake, it's very good news.
This is normal behavior for the request configuration you have.
It has to do with HTTP persistent connections.
Jetty 6's servlet tester defaulted to HTTP/1.0 behavior.
HTTP/1.0 has no official specification for persistent connections, but clients have evolved over the years to adopt a non-persistent behavior, which can be overridden with a negotiated Connection header.
With HTTP/1.0, its 1 request, then 1 response, then connection is closed. Unless the client sends a Connection: Keep-Alive header (and the server responds with the same header)
Jetty 9's HttpTester also defaults to HTTP/1.0.
You specified request.setVersion("HTTP/1.1"); in your example, where all connections are considered persistent unless declared otherwise. So adding Connection: close will force the server to close the connection after the response has been sent, not waiting for another request.
So you have 2 options here:
Stick with HTTP/1.1 and also add request.setHeader("Connection", "close");
or downgrade your HTTP version to 1.0. using either:
request.setVersion("HTTP/1.0");
or comment out the call to request.setVersion(); and rely on default behavior.
Related
I am trying to start a mock a server from Java and keep it running to receive incoming requests from other sources (Postman, CURL, etc).
I have tried the Junit approach, but when the unit tests finishes, the server is shutdown.
On the other hand, running the standalone version
http://www.mock-server.com/mock_server/running_mock_server.html#running_from_command_line
keeps the mock server running.
I would like to achieve the same thing, but from the Java code.
The question is, how may I make it run and stay running?
Thanks
So you need an HTTP server for non-testing purposes? I'd try with Spring, something like:
#RestController
public class CatchAllController {
#RequestMapping("/**")
public String catchAll(HttpServletRequest request) {
return request.getRequestURI();
}
}
There is an example on that same page (paragraph "Client API - starting and stopping"). This code works for me:
import static org.mockserver.integration.ClientAndServer.startClientAndServer;
import org.mockserver.integration.ClientAndServer;
public class Checker {
public static void main(String[] args) {
ClientAndServer mockServer = startClientAndServer(1080);
}
}
You have to call
mockServer.stop();
later to stop it.
You will need the following maven dependency:
<!-- mockserver -->
<dependency>
<groupId>org.mock-server</groupId>
<artifactId>mockserver-netty</artifactId>
<version>5.5.1</version>
</dependency>
I don't if this is even possible, which is why I thought I'd ask.
I forgot to mention I'm using Jersey 1.19 and Java 1.6.
I created a RESTful web service in Java using the Jersey API, as well as client code to call the web service. The client code is Jersey-based, as well. The problem I'm running into is I don't want to deploy the JAR file to the web server every time I make a change and want to test -- the web server is on a remote server and I"m coding on a local computer.
Is it possible to simulate a client-server web service call completely within the IDE (i.e. Eclipse)? In other words, I want to call the web service from my
local computer, without having to host it on a web server; no different than
calling a function.
Here is the client code:
package com.xyzcorp.webservices;
import javax.ws.rs.core.MediaType;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
public class RestClient {
public static void main(String[] args) {
Client client = Client.create();
/*
Right now, it's calling the web service on the web server.
I want to call this same web service but from within the code local
to my computer, without hosting it on a web server.
*/
WebResource webResource = client.resource("http://myserver.com/rest/ids/12345");
ClientResponse response = webResource.accept(MediaType.APPLICATION_JSON).get(ClientResponse.class);
if (response.getStatus() != 200) {
throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
}
}
}
Here is the web service code:
package com.xyzcorp.webservices;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.xyzcorp.webservices.EmpData;
#Path("/rest")
public class RestWebService {
#GET
#Path("/ids/{ids}")
#Produces(MediaType.APPLICATION_JSON)
public EmpData getEmpDataJSON(
#PathParam("ids") String ids)
...
return empData;
}
}
Is it possible to call the RestWebService class directly without having to use a web server? I.e. `WebResource webResource = client.resource(new RestWebService().EmpData("12345"));
Thank you very much.
Use Jersey Test Framework. Run (semi) Integration/Unit tests on your resources like you would a normal unit test. For example
public class MainTest extends JerseyTest {
public MainTest() throws Exception {
super("com.sun.jersey.samples.helloworld.resources");
}
#Test
public void testHelloWorld() {
WebResource webResource = resource();
String responseMsg = webResource.path("helloworld").get(String.class);
assertEquals("Hello World", responseMsg);
}
}
The JerseyTest will start and stop an embedded server for each test case. It could even be an in memory server (so as not to take so much load time) depending on what server dependency you want to use. Here's an example dependency
<dependency>
<groupId>com.sun.jersey.jersey-test-framework</groupId>
<artifactId>jersey-test-framework-grizzly2</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
The link I provided shows other dependencies you can use.
Here is another example usage (the bottom part is for Jersey 1.x - the top is 2.x)
This might be of use to you:
http://www.eclipse.org/webtools/community/education/web/t320/Implementing_a_Simple_Web_Service.pdf
particularly page 12 onwards.
Hope it helps.
EDIT : just in case, your machine URL will contain "localhost" for services running on your local computer.
I'm building a Jersey Moxy service using the quickstart archetype at the end. My code works fine and I can get some JSON returned. However as I'm developing, if I make a mistake, say the request handler has an unsupported type, I will get an empty 500 response, which makes debugging difficult. For example, if I decorate an attribute incorrectly with #XmlElementRef, I will get a response like:
$ curl -i http://localhost:8080/myapp/test
HTTP/1.1 500 Internal Server Error
Date: Thu, 05 Sep 2013 10:27:55 GMT
Connection: close
Content-Length: 0
The server will act as if nothing is wrong:
Sep 5, 2013 11:27:46 AM org.glassfish.grizzly.http.server.HttpServer start
INFO: [HttpServer] Started.
Jersey app started with WADL available at http://localhost:8080/application.wadl
Hit enter to stop it...
I tried using a log config file with:
-Djava.util.logging.config.file=log.conf
This produces plenty of output, but still doesn't show any kind of exception.
I've tried looking into Grizzly config but I can't find a way turn off graceful error handling. Ideally I would like the server to throw an exception. Any suggestions on what I'm missing?
Here's my main code:
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.moxy.json.MoxyJsonConfig;
import org.glassfish.jersey.server.ResourceConfig;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.net.URI;
import java.util.*;
public class Main {
// Base URI the Grizzly HTTP server will listen on
public static final String BASE_URI = "http://localhost:8080/";
/**
* Starts Grizzly HTTP server exposing JAX-RS resources defined in this application.
* #return Grizzly HTTP server.
*/
public static HttpServer startServer() {
// create a resource config that scans for JAX-RS resources and providers
// in com.myapp package
final ResourceConfig rc = new ResourceConfig().packages("com.myapp").registerInstances(new JsonMoxyConfigurationContextResolver());
// create and start a new instance of grizzly http server
// exposing the Jersey application at BASE_URI
return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
}
/**
* Main method.
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
final HttpServer server = startServer();
System.out.println(String.format("Jersey app started with WADL available at "
+ "%sapplication.wadl\nHit enter to stop it...", BASE_URI));
System.in.read();
server.stop();
}
#Provider
final static class JsonMoxyConfigurationContextResolver implements ContextResolver<MoxyJsonConfig> {
#Override
public MoxyJsonConfig getContext(Class<?> objectType) {
final MoxyJsonConfig configuration = new MoxyJsonConfig();
Map<String, String> namespacePrefixMapper = new HashMap<String, String>(1);
namespacePrefixMapper.put("http://www.w3.org/2001/XMLSchema-instance", "xsi");
configuration.setNamespacePrefixMapper(namespacePrefixMapper);
configuration.setNamespaceSeparator(':');
return configuration;
}
}
}
The code is almost identical to the example here:
https://github.com/jersey/jersey/tree/2.2/examples/json-moxy/src/main/java/org/glassfish/jersey/examples/jsonmoxy
Full archetype generation I used:
mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-grizzly2 \
-DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false \
-DgroupId=com.myapp -DartifactId=yarese-service -Dpackage=com.myapp \
-DarchetypeVersion=2.2
Suggestions gratefully received.
The exception is not getting propagated to the Grizzly layer, so it should be logged by Jersey. I haven't found what kind of Logger you have to enable, but looks like custom ExceptionMapper could help.
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import org.glassfish.grizzly.utils.Exceptions;
#Provider
public class MyExceptionMapper implements
ExceptionMapper<WebApplicationException> {
#Override
public Response toResponse(WebApplicationException ex) {
return Response.status(500).entity(Exceptions.getStackTraceAsString(ex)).type("text/plain")
.build();
}
}
As you've seen, Grizzly uses java.util.logging. If you'd like to see the stacktrace, you need to make sure the levels are correctly set in your log.conf file.
Here are settings that have worked for me in the past:
handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level=ALL
.level=ALL
org.glassfish.level=CONFIG
I am developing a RESTful service which has two severs talking to each other, which may be named as external and internal.
Internal registers requests to external for further processing. Only external is accessible to users.
For testing reliability my link between internal and external server, I want to simulate HTTP error as returned by external to internal. Is there any easy way to do so or I'll have to hardcode the response being sent by external to internal for testing mainly 5xx and 4xx errors.
Server I am using is JBoss if at all this info is needed.
On searching Google, I found this data for iPlanet
1. edit the obj.conf or your virtual server specific obj.conf
2. Add the following line under
Error code="200" fn="set-variable" error="503"
this would return 503 even for successful serving (which would cause 200 to be returned by the default).
I am looking for something similar for JBoss
I am not aware of a JBoss configuration that will allow you to do this outside of the application. But its easy enough to setup a Resource within your application that would simulate this behavior and remove dependency on vendor specific application server:
#GET #POST #PUT #DELETE
#Path("/echostatus/{statusCode}")
#Produces(MediaType.TEXT_PLAIN, MediaType.TEXT_HTML)
public Response echoStatus(#PathParam("statusCode") final Integer statusCode) {
return Response.status(statusCode.intValue()).build();
}
In my opinion, to test this integration, it would be much easier to develop simple stub web app that will return 5xx code for any URI. To make it more flexible, you can add some handles to be able to tweak behavior of this test app in run time (e.g. based on URI, on various parameters of the request, ...).
I am not aware of any component in JBoss that will do the thing with rewriting status code, but it is simple to do it on your own. Just write your own Tomcat Valve and put it in server.xml
import java.io.IOException;
import javax.servlet.ServletException;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;
public class RequestThroughputLimitValve extends ValveBase implements Lifecycle {
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// NOTE: THIS IS NOT COMPLETE IMPLEMENTATION
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
private int statusCode;
#Override
public void invoke(Request request, Response response) throws IOException, ServletException {
// Pass the request further, if necessary
getNext().invoke(request, response);
// Tweak the response
response.setContentType("text/plain");
response.sendError(this.statusCode, "Forced error.");
}
// This will make the status code configurable in valve
public void setStatusCode(int statusCode) {
this.statusCode = statusCode
}
public int getStatusCode() {
return this.statusCode;
}
}
It is very easy to produce error 500. Just throw exception into web service method. JBoss will generate response code 500.
Other way it to use HTTP Resptonse API. Just set status as you want. If you want you can write this code in HTTP filter that can be installed for testing purposes only. This way you can simulate any HTTP status (both 400 or 500 series)
I'm currently looking for ways to create automated tests for a JAX-RS (Java API for RESTful Web Services) based web service.
I basically need a way to send it certain inputs and verify that I get the expected responses. I'd prefer to do this via JUnit, but I'm not sure how that can be achieved.
What approach do you use to test your web-services?
Update: As entzik pointed out, decoupling the web service from the business logic allows me to unit test the business logic. However, I also want to test for the correct HTTP status codes etc.
Jersey comes with a great RESTful client API that makes writing unit tests really easy. See the unit tests in the examples that ship with Jersey. We use this approach to test the REST support in Apache Camel, if you are interested the test cases are here
You can try out REST Assured which makes it very simple to test REST services and validating the response in Java (using JUnit or TestNG).
As James said; There is built-in test framework for Jersey. A simple hello world example can be like this:
pom.xml for maven integration. When you run mvn test. Frameworks start a grizzly container. You can use jetty or tomcat via changing dependencies.
...
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.16</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework</groupId>
<artifactId>jersey-test-framework-core</artifactId>
<version>2.16</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>2.16</version>
<scope>test</scope>
</dependency>
</dependencies>
...
ExampleApp.java
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
#ApplicationPath("/")
public class ExampleApp extends Application {
}
HelloWorld.java
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
#Path("/")
public final class HelloWorld {
#GET
#Path("/hello")
#Produces(MediaType.TEXT_PLAIN)
public String sayHelloWorld() {
return "Hello World!";
}
}
HelloWorldTest.java
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import javax.ws.rs.core.Application;
import static org.junit.Assert.assertEquals;
public class HelloWorldTest extends JerseyTest {
#Test
public void testSayHello() {
final String hello = target("hello").request().get(String.class);
assertEquals("Hello World!", hello);
}
#Override
protected Application configure() {
return new ResourceConfig(HelloWorld.class);
}
}
You can check this sample application.
You probably wrote some java code that implements your business logic and then you have generated the web services end point for it.
An important thing to do is to independently test your business logic. Since it's pure java code you can do that with regular JUnit tests.
Now, since the web services part is just an end point, what you want to make sure is that the generated plumbing (stubs, etc) are in sync with your java code. you can do that by writing JUnit tests that invoke the generated web service java clients. This will let you know when you change your java signatures without updating the web services stuff.
If your web services plumbing is automatically generated by your build system at every build, then it may not be necessary to test the end points (assuming it's all properly generated). Depends on your level of paranoia.
Though its too late from the date of posting the question, thought this might be useful for others who have a similar question.
Jersey comes with a test framework called the Jersey Test Framework which allows you to test your RESTful Web Service, including the response status codes. You can use it to run your tests on lightweight containers like Grizzly, HTTPServer and/or EmbeddedGlassFish. Also, the framework could be used to run your tests on a regular web container like GlassFish or Tomcat.
I use Apache's HTTPClient (http://hc.apache.org/) to call Restful Services. The HTTP Client library allows you to easily perform get, post or whatever other operation you need. If your service uses JAXB for xml binding, you can create a JAXBContext to serialize and deserialize inputs and outputs from the HTTP request.
Take a look at Alchemy rest client generator. This can generate a proxy implementation for your JAX-RS webservice class using jersey client behind the scene. Effectively you will call you webservice methods as simple java methods from your unit tests. Handles http authentication as well.
There is no code generation involved if you need to simply run tests so it is convenient.
Dislclaimer: I am the author of this library.
Keep it simple. Have a look at https://github.com/valid4j/http-matchers which can be imported from Maven Central.
<dependency>
<groupId>org.valid4j</groupId>
<artifactId>http-matchers</artifactId>
<version>1.0</version>
</dependency>
Usage example:
// Statically import the library entry point:
import static org.valid4j.matchers.http.HttpResponseMatchers.*;
// Invoke your web service using plain JAX-RS. E.g:
Client client = ClientBuilder.newClient();
Response response = client.target("http://example.org/hello").request("text/plain").get();
// Verify the response
assertThat(response, hasStatus(Status.OK));
assertThat(response, hasHeader("Content-Encoding", equalTo("gzip")));
assertThat(response, hasEntity(equalTo("content")));
// etc...
An important thing to do is to independently test your business logic
I certainly would not assume that the person who wrote the JAX-RS code and is looking to unit test the interface is somehow, for some bizarre, inexplicable reason, oblivious to the notion that he or she can unit testing other parts of the program, including business logic classes. It's hardly helpful to state the obvious and the point was repeatedly made that the responses need to be tested, too.
Both Jersey and RESTEasy have client applications and in the case of RESTEasy you can use the same annoations (even factor out annotated interface and use on the client and server side of your tests).
REST not what this service can do for you; REST what you can do for this service.
As I understand the main purpose of the auther of this issue is to decouple JAX RS layer from business one. And unit test only the first one. Two basic problems here we have to resolve:
Run in test some web/application server, put JAX RS components in
it. And only them.
Mock business services inside JAX RS
components/REST layer.
The first one is solved with Arquillian.
The second one is perfectly described in arquillican and mock
Here is an example of the code, it may differ if you use another application server, but I hope you'll get the basic idea and advantages.
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import com.brandmaker.skinning.service.SomeBean;
/**
* Created by alexandr on 31.07.15.
*/
#Path("/entities")
public class RestBean
{
#Inject
SomeBean bean;
#GET
public String getEntiry()
{
return bean.methodToBeMoked();
}
}
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import com.google.common.collect.Sets;
/**
*/
#ApplicationPath("res")
public class JAXRSConfiguration extends Application
{
#Override
public Set<Class<?>> getClasses()
{
return Sets.newHashSet(RestBean.class);
}
}
public class SomeBean
{
public String methodToBeMoked()
{
return "Original";
}
}
import javax.enterprise.inject.Specializes;
import com.brandmaker.skinning.service.SomeBean;
/**
*/
#Specializes
public class SomeBeanMock extends SomeBean
{
#Override
public String methodToBeMoked()
{
return "Mocked";
}
}
#RunWith(Arquillian.class)
public class RestBeanTest
{
#Deployment
public static WebArchive createDeployment() {
WebArchive war = ShrinkWrap.create(WebArchive.class, "test.war")
.addClasses(JAXRSConfiguration.class, RestBean.class, SomeBean.class, SomeBeanMock.class)
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
System.out.println(war.toString(true));
return war;
}
#Test
public void should_create_greeting() {
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://127.0.0.1:8181/test/res/entities");
//Building the request i.e a GET request to the RESTful Webservice defined
//by the URI in the WebTarget instance.
Invocation invocation = target.request().buildGet();
//Invoking the request to the RESTful API and capturing the Response.
Response response = invocation.invoke();
//As we know that this RESTful Webserivce returns the XML data which can be unmarshalled
//into the instance of Books by using JAXB.
Assert.assertEquals("Mocked", response.readEntity(String.class));
}
}
A couple of notes:
JAX RS configuration without web.xml is used here.
JAX RS Client is used here (no RESTEasy/Jersey, they expose more convenient API)
When test starts, Arquillian's runner starts working. Here you can find how to configure tests for Arquillian with needed application server.
Depending on the chosen application server, an url in the
test will differ a little bit. Another port may be used. 8181 is
used by Glassfish Embedded in my example.
Hope, it'll help.