1

I am trying to unit test a Spring bean I implemented, but come across a difficulty here. This bean is to call a distant REST service on certain occasions.

However, in my tests, I would like it to call a mock servlet inside my test context, not a distant server.

The call is made using Apache's httpclient library, the URL is set in the applicationContext (so I can provide any fake URI to the bean when testing). The service should return a stream.

The call looks like the following:

HttpClient client = new DefaultHttpClient();
URIBuilder builder = new URIBuilder(theURIProvidedInContext);
// set parameters on builder
URI uri = builder.build();

HttpGet get = new HttpGet(uri);
HttpEntity entity = client.execute(get).getEntity();
return entity.getContent();

I searched Google all morning but only found how to unit-test servlets. Can anybody give some insight here?

Chop
  • 4,267
  • 5
  • 26
  • 58
  • How is this HTTP call made? Do you use some client library? Where does it get the URL to call from? –  Oct 10 '12 at 09:19
  • Sorry, I lacked precision on that one. I edited the question to amend that mistake. – Chop Oct 10 '12 at 09:28

2 Answers2

2

You're not going to be able to call a mock servlet in a test context because there's no application server. Instead, you can pull out that code that uses HTTP Client to make the call into a separate bean, and then mock that to return the desired stream.

If it's a REST service, you can create a JAX-RS annotated class as a test double (I won't call it a mock), and start it with an embedded server like Grizzly or Jersey. That will start up an HTTP server for you. Your annotated class can throw 404, 500, etc. depending on how you want the test to proceed. See JAX-RS with embedded server

Community
  • 1
  • 1
artbristol
  • 32,010
  • 5
  • 70
  • 103
  • I am surprised there is no way to start an embedded application server (or at least simulating one). I tinkered a little with SpringRemoting and tried to run an embedded Jetty, but I cannot configure it properly. Thank you for your answer, though: pulling the HTTP client logic will indeed allow me to have a better test coverage. – Chop Oct 10 '12 at 12:20
  • @Chop, Yes you certainly could start up Jetty in your test - I've done that on a number of projects. It all depends what you are aiming to test. For a *unit* test, it's better to mock out all the HTTP parts. – artbristol Oct 10 '12 at 12:31
  • Let's just say that I would like to be sure the bean behaves when the HTTP returns a 404 (did not find the stream to return) or 500 status. Mocking it only allows me to ensure everything works when everything is right on the other side (which might not always be the case). – Chop Oct 10 '12 at 12:54
  • @Chop In this case, I'd use JAX-RS rather than plain servlet. JAX-RS annotations make it dead easy to create and deploy an endpoint. See edit. – artbristol Oct 10 '12 at 12:58
  • As a matter of fact, I had some problems with Endpoint (designed for JAX-WS more than JAX-RS). Yet, with some searches, I found how to use a Grizzly embedded server with a Jersey annotated file instead (for some code, see here: http://stackoverflow.com/questions/8277409/jax-rs-with-embedded-server). Thanks for hinting the way! – Chop Oct 11 '12 at 08:34
  • @Chop Sorry about the mixup! I'll update my answer. Glad you got it to work. – artbristol Oct 11 '12 at 08:39
1

Try com.rexsl.test.ContainerMocker from com.rexsl:rexsl-test:mock:0.3.8 (I'm a developer):

URI home = new ContainerMocker()
  .expectMethod("GET")
  .expectHeader("Accept", Matchers.startsWith("text/"))
  .returnBody("<done/>")
  .returnStatus(200)
  .mock()
  .home();

Now you have a URI with a running HTTP container, which you can inject it into your classes.

yegor256
  • 102,010
  • 123
  • 446
  • 597