TLDR: when I have a small set of HTTP use-cases, and I’m working on fast in-build HTTP integration verification then I’ll probably use HttpURLConnection
I do receive a question fairly often like:
- “Why would you ever use basic HTTP libraries rather than Rest-Assured?”
- “When would you choose to use basic HTTP libraries instead of Rest-Assured?”
And other variants.
I’ll try to answer that in this post.
It isn’t an easy answer since I’ll know it when I see it.
But… since I’ve just implemented a bunch of @Test methods for a test app that I’m writing and they use the HttpURLConnection
I will explain my reasoning for that.
Case Study 1 - Fast, Light, Local HTTP Verification
Most of my test apps use Spark as their embedded Web Server.
- easy to use
- fairly small
- easy to start up for testing purposes
Locally Running Server
And by easy to start up for testing purposes I mean easy.
@BeforeClass
public static void ensureAppIsRunning(){
CompendiumAppsAndGamesSparkStarter.
get("localhost", "/heartbeat" ).
startSparkAppIfNotRunning(4567);
}
Clearly the above is an abstraction layer, and I’ll explain that in a future post, but I can have a single line of code in an @BeforeClass
method that will quickly startup my app, listening on a port ready for me to send HTTP requests as local integration tests.
I put these in a separate package to my super fast Unit tests, but these usually run fast enough that I don’t do anything special to separate them out in my build process.
Send HTTP messages
Because my test app is running locally as part of my JUnit execution, I want any @Test
methods to run quickly and have minimal maintenance.
I decided to use the built in Java HttpURLConnection
rather than an external library.
Why?
- no additional dependencies required
- stable API
- minimal changes between Java versions
I recently had to change my HttpURLConnection
wrapper abstractions to cope with Java 1.9 reflection changes, but that was because I had essentially hacked the HttpURLConnection
to gain access to the raw message sent. Otherwise I haven’t really had to change my code very often.
With RestAssured (or any third party HTTP library), I have to be very conscious of the version I use, and I might find I have to update my project and change my code just to keep the version of Java advancing.
Using HttpURLConnection
keeps my life as a programmer simple.
Why not use the Java 1.9 HTTP2 library?
And over the years I’ve build up abstraction code to help me that I move between projects. Cod that I will eventually put into a support library, at some point, probably just when the Java 10 HTTP 2 library is released thereby making my abstraction code instantly redundant.
I think the HTTP2 library is still in []incubator mode](https://dzone.com/articles/an-introduction-to-http2-support-in-java-9) and will probably change for Java 10 so at the moment it feels like a third party library which would add stress into my code, rather than make things easy.
Prefer built in libraries
I try to use built in libraries where possible to reduce the size of my project and the amount of stuff I have to learn that might not be transferrable to other work.
The build in HttpURLConnection
isn’t perfect but a quick layer of abstraction layer and it works well in situations where you do not require a lot of flexibility and edge case processing. For my testing I will mainly issue some GET
, and POST
requests, and won’t really do much error processing.
How do you use HttpURLConnection
I will have an @Test
that looks a bit like this:
@Test
public void canAccessiframeSearch(){
http = new BasicHttp("http","localhost", 4567);
Assert.assertTrue(http.isPageAt("/apps/iframe-search/iframe-search.html"));
}
And you can see I’ve hidden HttpURLConnection
behind a BasicHttp
abstraction, so if I do want to do anything more complicated I can change that abstraction layer to delegate off to a third party library instead of using the HttpUrlConnection
. And my @Test
code won’t have to change.
So, what’s in the box at isPageAt
?
Make an HTTP request
isPageAt
basically makes an HTTP request
HttpURLConnection con = (HttpURLConnection)new URL(protocol,host, port, path).openConnection();
int status = con.getResponseCode();
if(status==200){
return true;
}else{
return false;
}
For a simple ping
test, HttpURLConnection
gives me what I need without any third party libraries and it works fast.
Running on localhost
as a simple embedded server means I don’t have any complicated connections.
HttpURLConnection
works well here.
Get the Body
I do sometimes want to go beyond ping
and get the body of the request. And HttpURLConnection
does make you work a little harder at this point to get the request body.
private String getResponseBody(HttpURLConnection con) {
BufferedReader in=null;
// https://stackoverflow.com/questions/24707506/httpurlconnection-how-to-read-payload-of-400-response
try {
in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
}catch(Exception e){
// handle 400 exception messages
InputStream stream = con.getErrorStream();
if(stream!=null) {
in = new BufferedReader(
new InputStreamReader(stream));
}
}
String inputLine;
StringBuffer responseBody = new StringBuffer();
try{
if(in!=null) {
while ((inputLine = in.readLine()) != null) {
responseBody.append(inputLine);
}
in.close();
}
}catch(IOException e){
e.printStackTrace();
}
return responseBody.toString();
}
The above code:
- read the input stream
- if that fails get the error stream
- now read which ever one it was itno a
StringBuffer
- then convert that to a
String
and return it
Bit of a pain, but having copy and pasted the code from Stackoverflow into your own abstraction layers you never really have to worry about it again.
And so it goes on
HttpURLConnection
can handle proxy connections, PUT
, POST
, custom headers etc. So your abstraction layer for your use case grows to cover what you need it to do.
You only have to write code to cover the situations you test for.
If you find that your abstraction layer is starting to balloon out of control and you are maintaining it more then it is probably time to consider bringing in a third part abstraction like RestAssured to minimise your work load.
So…
I tend to use HttpURLConnection
as default instead of a third party library like RestAssured when:
- running fast integration tests
- constrained use case for the HTTP requests
- want to keep dependencies to a minimum
- happy to write abstraction code around HTTP requests (but not too much)
- want to minimise impact of Java version upgrades
Also note that the @Test
methods here are strategic in that they are a long-term automated execution approach. But they are also part of the early ‘build’ process.
When they are part of my ‘integration’ test process I’ll probably use RestAssured as the default choice because I will be expecting a less constrained set of use cases for the HTTP requests and I’ll probably be coding in a different project than the main code project so dependency management will be less of an issue.
References
You can find the code I’ve referred to here on Github if you want to trawl through the project:
And you can find a slightly bigger set of HttpURLConnection
abstractions here at some point I’ll pull these out into their own library.