Daniel Kamil Kozar
Daniel Kamil Kozar

Reputation: 19276

How to unit test a class which uses HttpURLConnection internally?

I'm looking for the best way to test a class which internally makes HTTP requests to a pre-defined URL. Generally, the class in question looks more or less like this :

public class ServiceAccess {
    private static final String SERVICE_URL = "http://someservice.com/";
    public ServiceAccess(String username) throws IOException, 
        UserNotFoundException, MalformedURLException {
        URL url = new URL(SERVICE_URL + username);
        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
        if(conn.getResponseCode() == HTTP_NOT_FOUND) {
            throw new UserNotFoundException("user not found : " + username);
        }
        // and some more checks
    }
}

I would like to test that the class properly reacts to the HTTP server's responses, including response codes, header fields, and such. I found the mockwebserver library that looks just like something I need. However, in order to use it, I would need to somehow change the URL that the class connects to.

The only sensible option that I see is to pass the URL in the constructor : however, it seems to me that this does not play too well in terms of design, since requiring the client to pass an URL to such a class looks fishy. Furthermore, I have not seen any other web service access libraries (Twitter4J, RestFB) that would require their clients to pass the URL in order to actually use them.

I'm not a Java whiz, but I'd like to get it as right as possible. All answers welcome.

Upvotes: 2

Views: 3545

Answers (3)

piotrek
piotrek

Reputation: 14540

if you have written your tests first, you would have never written such code :)

your class violates single responsibility rule. refactor this class. extract part responsible for networking (in your code - getting connection). then ServiceAccess should use that class. then you can easily test ServiceAccess in unit tests. unit testing networking code is pointless - guys from oracle have already done that. all you can test is that you have provided correct parameters and that's the role of integration tests

Upvotes: 1

Martin Schröder
Martin Schröder

Reputation: 4591

Iff you can't change the code, you could use PowerMock to mock HttpURLConnection.

Upvotes: 0

Rob
Rob

Reputation: 11733

What is fishy about passing the URL? Not sure I get that.

Generally for things like this, don't you want the URL to be a property? I would think in the same way that the database url for your instance is going to be constructed of properties, you would want to do the same here. In which case, in your test you just override the property/ies.

The other interesting thing about these kinds of tests is I think it's a really good idea to have tests of the actual protocol (which is what you are doing with the mock) and also the actual service and then run the service tests on a schedule, just as a way to make sure that the downstream services you are consuming are still there and honoring their end of the contract. Was reading the excellent Continuous Delivery book from Addison Wesley, contemplating making this part of a pipeline today.

Upvotes: 2

Related Questions