Reputation: 971
I'm writing integration JUnit test. My task is to test whether the response of my local server is correct. The mentioned server takes as a GET parameter an address of page to be analysed (for example: localhost:8000/test?url=http://www.example.com
).
To avoid being dependent on www.example.com I want to start for this particular test my own jetty server, which always serves the same content.
private static class MockPageHandler extends AbstractHandler {
public void handle(String target,Request baseRequest, HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("text/html; charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
final String responseString = loadResource("index.html");
response.getWriter().write(responseString);
baseRequest.setHandled(true);
}
}
public void test() throws Exception {
final int PORT = 8080;
final Server server = new Server(PORT);
server.setHandler(new MockPageHandler());
server.start();
final ContentResponse response =
client.newRequest("http://localhost:8000/test?url=http://localhost:8080").send();
/* some assertions. */
server.stop();
server.join();
}
Every time I execute this test, the handle
method in MockPageHandler
is never invoked.
Do you have any suggestions why this not works?
P.S. When I remove server.stop()
and in browser type http://localhost:8080
the proper page is shown.
Upvotes: 2
Views: 3428
Reputation: 15
Give a try to "com.jayway.restassured" for your http test. too easy to write some test :
@Test
public void testNotGetAll() {
expect().
statusCode(404).
when().
get(baseUrl+"/games/");
}
this method call "http://mywebserver.local:8080/rest/games/" and verify that a 404 http status code is returned.
And this approach synchronised with a Jetty server (for example) started at pre-integration-test in the maven lifecycle, you match the perfect mix to process integration test !
Upvotes: 0
Reputation: 49462
Quick answer:
Remove the server.join()
line. That line makes the junit thread wait until the server thread stops. Which is not needed for unit testing.
Long answer:
What we (the jetty developers) have learned about using jetty embedded servers with junit.
Use the @Before
and @After
annotations to start and stop the server if you have 1 test method, or some requirement that the server be pristine between test methods.
Example @Before / @After (Jetty 9.x):
public class MyTest
{
private Server server;
private URI serverUri;
@Before
public void startServer() throws Exception
{
this.server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(0); // let connector pick an unused port #
server.addConnector(connector);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
server.setHandler(context);
// Serve capture servlet
context.addServlet(new ServletHolder(new MyServlet()),"/my/*");
// Start Server
server.start();
String host = connector.getHost();
if (host == null)
{
host = "localhost";
}
int port = connector.getLocalPort();
this.serverUri = new URI(String.format("http://%s:%d/",host,port));
}
@After
public void stopServer()
{
try
{
server.stop();
}
catch (Exception e)
{
e.printStackTrace(System.err);
}
}
@Test
public void testMe()
{
// Issue request to server
URI requestUri = serverUri.resolve("/my/test");
// assert the response
}
}
This technique makes the server start on port 0, which is a magic number that tells the underlying stack to pick an empty port and start listening. The test case then asks the server what port number it is listening on and builds out the serverUri
field to be appropropriate for this test run.
This technique works great, however, it will start/stop the server for each method.
Enter, the better technique, use the @BeforeClass
and @AfterClass
annotations to start/stop the server once for the entire test class, running all of the methods inside of the test class against this started server.
Example @BeforeClass / @AfterClass (Jetty 9.x):
public class MyTest
{
private static Server server;
private static URI serverUri;
@BeforeClass
public static void startServer() throws Exception
{
server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(0); // let connector pick an unused port #
server.addConnector(connector);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
server.setHandler(context);
// Serve capture servlet
context.addServlet(new ServletHolder(new MyServlet()),"/my/*");
// Start Server
server.start();
String host = connector.getHost();
if (host == null)
{
host = "localhost";
}
int port = connector.getLocalPort();
serverUri = new URI(String.format("http://%s:%d/",host,port));
}
@AfterClass
public static void stopServer()
{
try
{
server.stop();
}
catch (Exception e)
{
e.printStackTrace(System.err);
}
}
@Test
public void testMe()
{
// Issue request to server
URI requestUri = serverUri.resolve("/my/test");
// assert the response
}
}
Doesn't look much different? Yes, the changes are subtle. @Before
became @BeforeClass
, @After
became @AfterClass
. The start/stop methods are now static. The server
and serverUri
fields are now static.
This technique is used where we have dozens of test methods that access the same server, and those requests do not alter the state in the server. This speeds up the test case execution by simply not recreating the server between each test method.
Upvotes: 5