OK, here is what I want to do as a TDD developer. Sorry for
such a long email. I've tried to simplify my code as much as
possible for this post, and may have missed in cases.
First lets assume I have a class used inside a Jersey resource
for its implementation:
package foo;
@Component
public class BarImpl implements Bar {
public String getHello(long id) throws BarException {
if (id == -1) {
throw new BarException("No such user: " + id);
}
return "Hello " + id;
}
}
That BarException is in package foo.exceptions and totally trivial.
The Bar interface is also totally trivial.
Now this is my resource class:
package foo.resource;
@Path("/hello")
@Component
public class BarResource {
@Autowired
private Bar bar;
@GET
@Produces("text/plain")
public String getHello(@QueryParam("id") long id) throws BarException {
return bar.getHello(id);
}
public void setBar(Bar bar) {
this.bar = bar;
}
}
Now, lets test this baby with JUnit. I write an applicationContext-test.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans LOTS OF XML MUMBO JUMBO>
<bean id="bar" class="foo.BarImpl">
</bean>
<bean id="barResource" class="foo.resource.BarResource">
<property name="bar" ref="bar"/>
</bean>
</beans>
The JUnit test of the resource class is a beauty of simplicity:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/applicationContext-test.xml" })
public class BarResourceTest {
@Autowired
private BarResource barResource;
@Test
public void testWithBogusId() {
try {
/* IGNORE RETURNED VALUE */ barResource.getHello(-1);
Assert.fail();
}
catch (BarException e) {
String message = e.getMessage();
Assert.assertEquals(message, "No such user: -1");
}
}
@Test
public void testWithOkId() throws BarException {
String message = barResource.getHello(77);
Assert.assertEquals(message, "Hello 77");
}
}
Now, how do I test this resource over HTTP? A complicating issue is that
I have an exception mapper:
@Provider
public class BarExceptionMapper implements ExceptionMapper<BarException> {
public Response toResponse(BarException e) {
return Response.status(Response.Status.NOT_FOUND).
entity(e.toString()).type("text/plain").build();
}
}
My (probably totally naive) attempt was this, from looking all over the
net for examples:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/applicationContext-test.xml" })
public class BarResourceRestTest {
private static final String baseUri = "
http://localhost:9998/";
private static final String resourcePackage =
BarResource.class.getPackage().getName();
private static final String exceptionMapperPackage =
BarExceptionMapper.class.getPackage().getName();
private SelectorThread threadSelector;
@Before
public void setup() throws IllegalArgumentException, IOException {
final Map<String, String> initParams = new HashMap<String, String>();
initParams.put("com.sun.jersey.config.property.packages",
resourcePackage + ";" + exceptionMapperPackage);
initParams.put("com.sun.jersey.config.property.resourceConfigClass",
"com.sun.jersey.api.core.PackagesResourceConfig");
threadSelector = GrizzlyWebContainerFactory.create(baseUri, initParams);
}
@After
public void shutDown() {
threadSelector.stopEndpoint();
}
@Test
public void testWithBogusId() throws IOException {
URL url = new URL(baseUri + "hello/-1");
String data = getDataFromUrl(url);
Assert.assertTrue(data.equals("No such user: -1"));
}
@Test
public void testWithOkId() throws IOException {
URL url = new URL(baseUri + "hello/77");
String data = getDataFromUrl(url);
Assert.assertTrue(data.equals("Hello 77"));
}
private String getDataFromUrl(URL url) throws IOException {
// Read all the text returned by the server
BufferedReader in = new BufferedReader(
new InputStreamReader(url.openStream()));
StringBuffer data = new StringBuffer(1000);
String line;
while ((line = in.readLine()) != null) {
data.append(line);
}
in.close();
return data.toString();
}
}
I can't get this to work. I've fiddled with various things, and I either
get a NullPointer where the bar object is used in this function:
public String getHello(@QueryParam("id") long id) throws BarException {
return bar.getHello(id);
}
Or, I get an exception, because the ExceptionMapper isn't in place.
I clearly don't want to fiddle with web.xml. I just want to deploy my
resource in Grizzly (or whatever standalone container) and make an HTTP
call. I would also prefer not to embed GlassFish in my JUnit tests.
We use WebLogic, but not in our JUnit tests, of course.
Mats