Using Sun Java 6 HttpServer to write a functional HTTP test
来源:互联网 发布:网络大v最有名的有哪些 编辑:程序博客网 时间:2024/04/28 20:36
Forces
At work, we recently had the need to perform functional testing of a custom client that used HTTP as a transport. This isn’t strictly unit testing since we’re conducting actual HTTP over a socket & port instead of stubbing out or mocking the server, but in this case that was the only real way to test the client.
I could’ve fired up a standalone Web server and used that, but decided against it for a couple of reasons.
First, I wanted to have the server respond in a specific way to a particular client request. For example, if the request was forGET /1234.xml
I might want to respond with an HTTP 200
and an XML response body. Another request forGET /0.xml
might return an HTTP 404
instead.
To do that using, say, a Servlet container would mean writing multiple Servlets (mapped to various request URI) or a ‘rich’ Servlet with additional complexity. I didn’t want to have to write tests to test my test scaffolding!
Secondly, a standalone server would have to be started and stopped outside of our standard compile/test/package process (usingMaven). Other people wouldn’t be able to run the tests successfully without having the test server up as well.
Clearly, the best way to go was to use an embedded HTTP server, which would allow us to provide specific responses tailored for each unit test.
As luck would have it, it turns out that Sun’s Java 6 implementation comes with a lightweight HTTP server API built in. Read on as I demonstrate the basic use of Sun’s HTTP server classes to write a functional test.
HTTP server in a box
The heart of our test solution involves taking advantage of the lightweight HTTP server API included in Sun’s Java 6 implementation. Note that since this isn’t part of the Java core API this package may not be available on all Java platforms. If this is a problem, you might be better off using another embedded HTTP server such as Jetty.
The class itself is com.sun.net.httpserver.HttpServer, and here’s how to use it in a nutshell:
- Create the server
- Create a server context and register a request handler
- Start the server
- Perform your test
- Stop the server, and verify/assert your expected behavior
Now let’s look at each step in detail with corresponding code.
Create the server
We create an HttpServer
using HttpServer.create()
. To specify a port, we need to pass in anInetSocketAddress
:
HttpServer httpServer = HttpServer.create(address, 0);
The second parameter to HttpServer.create()
is the ‘backlog’, “the maximum number of queued incoming connections to allow on the listening socket”. Since that doesn’t really affect us, we can just pass in a0
and a system default value is used.
Creating and registering a request handler
Now we get to the meat of actually stubbing our server’s behavior by creating and registering a request handler.HttpServer
provides the createContext(String path, HttpHandler handler)
method to do just that.
Now, HttpHandler
is an interface which declares one method:handle(HttpExchange)
Obviously, HttpExchange
is the class we need to work with when responding to HTTP requests. Let’s look at some code and I’ll explain what it does afterwards:
public void handle(HttpExchange exchange)throws IOException {
byte[] response= "<?xml version=\"1.0\"?>\n<resource id=\"1234\" name=\"test\" />\n".getBytes();
exchange.sendResponseHeaders(HttpURLConnection.HTTP_OK,
response.length);
exchange.getResponseBody().write(response);
exchange.close();
}
};
Basically: we convert our response string into a byte array. We send an HTTP 200
(OK) along with the number of bytes we’re about to send as the response body. We then write out the bytes of our response body, then close theHttpExchange
. The complete HttpExchange
life cycle is detailed in itsAPI documentation.
We now create a context for the URI we’re interested in, passing in our newly createdHttpHandler
, then start the server:
httpServer.start();
At this point, an actual HTTP server will start running in a background thread ready to respond to requests. Let’s exercise our client code:
URLConnection conn = url.openConnection();
BufferedReader in = new BufferedReader(newInputStreamReader(conn.getInputStream()));
assertEquals("<?xml version=\"1.0\"?>", in.readLine());
assertEquals("<resource id=\"1234\" name=\"test\" />", in.readLine());
Our client code connects to our server, retrieves the associated URI, then, using aBufferedReader
reads in lines from the input stream. We make a few JUnit assertions on what we received.
The only thing left to do is to stop our HttpServer
:
The parameter is the number of seconds (NOTE: not milliseconds) to block to wait for ourHttpServer
to shutdown properly. Since we know we’re not serving any other requests, we can safely tell ourHttpServer
to shut down immediately.
At a glance
Here’s our functional test at a glance:
InetSocketAddress address = new InetSocketAddress(8000);
HttpServer httpServer = HttpServer.create(address, 0);
// create and register our handler
HttpHandler handler = new HttpHandler(){
public void handle(HttpExchange exchange)throws IOException {
byte[] response= "<?xml version=\"1.0\"?>\n<resource id=\"1234\" name=\"test\" />\n".getBytes();
exchange.sendResponseHeaders(HttpURLConnection.HTTP_OK,
response.length);
exchange.getResponseBody().write(response);
exchange.close();
}
};
httpServer.createContext("/1234.xml", handler);
// start the server
httpServer.start();
// verify our client code
URL url =new URL("http://localhost:8000/1234.xml");
URLConnection conn = url.openConnection();
BufferedReader in = new BufferedReader(newInputStreamReader(conn.getInputStream()));
assertEquals("<?xml version=\"1.0\"?>", in.readLine());
assertEquals("<resource id=\"1234\" name=\"test\" />", in.readLine());
// stop the server
httpServer.stop(0);
While functional, I find the above code rather verbose. If I want to write more HTTP tests, I certainly don’t want to keep repeating myself goinghttpServer.start();
… httpServer.stop(0);
. I especially find it tedious to have to compute the length of the HTTP response body beforehand, then send it along with our HTTP response codebefore writing out the actual body.
- Using Sun Java 6 HttpServer to write a functional HTTP test
- How to write good test cases using Robot Framework
- Using Mockito to Unit Test Java Applications
- A note about how to write test plan
- How to Model and Implement a Domain Specific Language (DSL) for Functional Test Automation
- java HttpServer构建http服务器
- java HttpServer构建http服务器
- java HttpServer构建http服务器
- java HttpServer构建http服务器
- how to write a minimal http server/client
- how to write a nginx module for http living stream
- Using Zoundry to write bolg
- Assinging Values Using Write to
- To be a sun
- If you would like to submit a bug report, please visit:http://java.sun.com/webapps/bugreport/crash.j
- Write a program to convert string to number without using library function。
- Java Code Examples for com.sun.net.httpserver.HttpExchange.getResponseHeaders()
- Write a program to print the fibonacci series sum upto a particular no. using recursion.
- C#上传图片以及级图片打水印
- 在PHP5中使用DOM控制XML
- php的ob_start来生成静态页面
- ASP.NET 安全认证(四)
- 剖析PHP中的输出缓冲 flush之类
- Using Sun Java 6 HttpServer to write a functional HTTP test
- PHP cookie和session的分析(转)
- sqlite在多线程下的应用
- PHP 判断常量,变量和函数是否存在
- PHP异常处理
- Simple Java HTTPS server
- jQuery学习笔录2(jQuery学习笔记——选择器(2)&过滤器)
- PHP购物车类
- 五种开源协议的比较(BSD,Apache,GPL,LGPL,MIT) – 整理