How to test a Jersey REST web service? - java

I have written a Restful Web service and have to test it using JUnit4. I have already written a Client using Jersey Client. But want to know if I can test my service only with junit4. Can someone help me with sample at least.
My rest service has authenticate method that takes user name, password and returns a token.
I have written test case for authenticate method. But I am not sure how to test using url.
public class TestAuthenticate {
Service service = new Service();
String username = "user";
String password = "password";
String token;
#Test(expected = Exception.class)
public final void testAuthenticateInputs() {
password = "pass";
service.authenticate(username, password);
}
#Test(expected = Exception.class)
public final void testAuthenticateException(){
username = null;
String token = service.authenticate(username, password);
assertNotNull(token);
}
#Test
public final void testAuthenticateResult() {
String token = service.authenticate(username, password);
assertNotNull(token);
}
}

If you want to test using the URL, then you will need to start a server from your test. You can explicitly start an embedded server, which is pretty common for tests. Something like
public class MyResourceTest {
public static final String BASE_URI = "http://localhost:8080/api/";
private HttpServer server;
#Before
public void setUp() throws Exception {
final ResourceConfig rc = new ResourceConfig(Service.class);
server = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
}
#After
public void tearDown() throws Exception {
server.stop();
}
#Test
public void testService() {
Client client = ClientBuilder.newClient();
WebTarget target = client.target(BASE_URI).path("service");
...
}
}
It's basically an integration test. You're starting the Grizzly container and loading a ResourceConfig to the server with only the Service class. Of course you could add more classes to the configuration. You can use "real" resource config if you wanted.
The above test uses this dependency
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
<version>${jersey2.version}</version>
</dependency>
Another option, which is the one I prefer, is to make use of the Jersey Test Framework, which will start an embedded container for you. A test might look something more like
public class SimpleTest extends JerseyTest {
#Override
protected Application configure() {
return new ResourceConfig(Service.class);
}
#Test
public void test() {
String hello = target("service").request().get(String.class);
}
}
Using this dependency
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>${jersey2.version}</version>
<scope>test</scope>
</dependency>
And embedded Grizzly container will get started under the hood, with your ResourceConfig configuration. In both examples above it is assumed the #Path value for the Service class is service, as you can see in the test URLs.
Some Resources
Jersey 2 Test Framework user guide
Some Examples
How to write Unit Test for this class using Jersey 2 test framework
How to in-memory unit test Spring-Jersey
Example with Mockito, Test Framework, and Jersey 2
Example with Mockito, Test Framework, and Jersey 1
UPDATE
If you're not using Maven, here are the jars you will need to run an embedded Grizzly container for the Jersey Test Fraemwork
I usually search for all my jars here. You can select the version and there should be a link in the next page, to download. You can use the search bar to search for the others.
Here's a simple running example, once you have all the jars
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.core.DefaultResourceConfig;
import com.sun.jersey.spi.container.servlet.WebComponent;
import com.sun.jersey.test.framework.JerseyTest;
import com.sun.jersey.test.framework.WebAppDescriptor;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import junit.framework.Assert;
import org.junit.Test;
public class SimpleTest extends JerseyTest {
#Path("service")
public static class Service {
#GET
public String getTest() { return "Hello World!"; }
}
public static class AppConfig extends DefaultResourceConfig {
public AppConfig() {
super(Service.class);
}
}
#Override
public WebAppDescriptor configure() {
return new WebAppDescriptor.Builder()
.initParam(WebComponent.RESOURCE_CONFIG_CLASS,
AppConfig.class.getName())
.build();
}
#Test
public void doTest() {
WebResource resource = resource().path("service");
String result = resource.get(String.class);
Assert.assertEquals("Hello World!", result);
System.out.println(result);
}
}
You're most likely not going to have the resources and ResourceConfig in the same class as the test, but I just want to keep it simple and all visible in one class.
Whether you are using a web.xml or a ResourceConfig subclass (as shown above), you can cut down what you test by using a separate ResourceConfig, built in the test class, as I have done. Otherwise, if you are using your normal ResourceConfig class, you can just replace it in the configure method.
The configure method, is pretty much just building a web.xml file, just in Java code. You can see different methods in the WebAppDescriptor.Builder, like initParam, which is the same as an <init-param> in your web xml. You can simply use the string in the arguments, but there are some constants, as I used above.
The #Test is you usual JUnit test that will run. It is using the Jersey Client. But instead of creating the Client, you can simply just use the preconfigured Client by just accessing the resource() method, which returns a WebResource. If you are familiar with the Jersey Client, then this class should not be new to you.

Take a look at Alchemy rest client generator. This can generate a proxy implementation for your JAX-RS webservice class using jersey client behind the scene. Effectively you will call you webservice methods as simple java methods from your unit tests. Handles http authentication as well.
There is no code generation involved if you need to simply run tests so it is convenient.
The demo here setup up grizzly and uses the generator above to run junit tests.
Disclaimer: I am the author of this library.

I think #peeskillet has given you the needed prerequisites, i.e you need to run your web-service in an embedded web server. You could also look into dropwizard or spring-boot support for doing this conveniently.
As for actually verifying the response I would keep it simple and go with JUnit & http-matchers (see https://github.com/valid4j/http-matchers)

Related

Micronaut Embedded Server vs localhost

I'm getting started with micronaut and I would like to understand the difference between testing the controller using local host and using an Embedded server
For example
I have a simple controller
#Controller("/hello")
public class HelloController {
#Get("/test")
#Produces(MediaType.TEXT_PLAIN)
public String index() {
return "Hello World";
}
}
and the tested class
#MicronautTest
public class HelloControllerTest {
#Inject
#Client("/hello")
RxHttpClient helloClient;
#Test
public void testHello() {
HttpRequest<String> request = HttpRequest.GET("/test");
String body = helloClient.toBlocking().retrieve(request);
assertNotNull(body);
assertEquals("Hello World", body);
}
}
I got the logs:
14:32:54.382 [nioEventLoopGroup-1-3] DEBUG mylogger - Sending HTTP Request: GET /hello/test
14:32:54.382 [nioEventLoopGroup-1-3] DEBUG mylogger - Chosen Server: localhost(51995)
But then, in which cases we need an Embedded Server? why?
where I can find documentation to understand it. I read the documentation from Micronaut but is not clear for me, what is actually occurring and why?
like this example:
#Test
public void testIndex() throws Exception {
EmbeddedServer server = ApplicationContext.run(EmbeddedServer.class);
RxHttpClient client = server.getApplicationContext().createBean(RxHttpClient.class, server.getURL());
assertEquals(HttpStatus.OK, client.toBlocking().exchange("/hello/status").status());
server.stop();
}
In both cases, you are using EmbeddedServer implementation - NettyHttpServer. This is an abstraction that represents Micronaut server implementation (a NettyHttpServer in this case).
The main difference is that micronaut-test provides components and annotations that make writing Micronaut HTTP unit tests much simpler. Before micronaut-test, you had to start up your application manually with:
EmbeddedServer server = ApplicationContext.run(EmbeddedServer)
Then you had to prepare an HTTP client, for instance:
HttpClient http = HttpClient.create(server.URL)
The micronaut-test simplifies it to adding #MicronautTest annotation over the test class, and the runner starts the embedded server and initializes all beans you can inject. Just like you do with injecting RxHttpClient in your example.
The second thing worth mentioning is that the #MicronautTest annotation also allows you to use #MockBean annotation to override existing bean with some mock you can define at the test level. By default, #MicronautTest does not mock any beans, so the application that starts reflect 1:1 application's runtime environment. The same thing happens when you start EmbeddedServer manually - this is just a programmatic way of starting a regular Micronaut application.
So the conclusion is quite simple - if you want to write less boilerplate code in your test classes, use micronaut-test with all its annotations to make your tests simpler. Without it, you will have to manually control all things (starting Micronaut application, retrieving beans from application context instead of using #Inject annotation, and so on.)
Last but not least, here is the same test written without micronaut-test:
package com.github.wololock.micronaut.products
import io.micronaut.context.ApplicationContext
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpStatus
import io.micronaut.http.client.HttpClient
import io.micronaut.http.client.RxHttpClient
import io.micronaut.http.client.exceptions.HttpClientResponseException
import io.micronaut.runtime.server.EmbeddedServer
import spock.lang.AutoCleanup
import spock.lang.Shared
import spock.lang.Specification
class ProductControllerSpec extends Specification {
#Shared
#AutoCleanup
EmbeddedServer server = ApplicationContext.run(EmbeddedServer)
#Shared
#AutoCleanup
HttpClient http = server.applicationContext.createBean(RxHttpClient, server.URL)
def "should return PROD-001"() {
when:
Product product = http.toBlocking().retrieve(HttpRequest.GET("/product/PROD-001"), Product)
then:
product.id == 'PROD-001'
and:
product.name == 'Micronaut in Action'
and:
product.price == 29.99
}
def "should support 404 response"() {
when:
http.toBlocking().exchange(HttpRequest.GET("/product/PROD-009"))
then:
def e = thrown HttpClientResponseException
e.status == HttpStatus.NOT_FOUND
}
}
In this case, we can't use #Inject annotation and the only way to create/inject beans is to use applicationContext object directly. (Keep in mind that in this case, RxHttpClient bean does not exist in the context and we have to create it - in micronaut-test case this bean is prepared for us upfront.)
And here is the same test that uses micronaut-test to make the test much simpler:
package com.github.wololock.micronaut.products
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpStatus
import io.micronaut.http.client.HttpClient
import io.micronaut.http.client.annotation.Client
import io.micronaut.http.client.exceptions.HttpClientResponseException
import io.micronaut.test.annotation.MicronautTest
import spock.lang.Specification
import javax.inject.Inject
#MicronautTest
class ProductControllerSpec extends Specification {
#Inject
#Client("/")
HttpClient http
def "should return PROD-001"() {
when:
Product product = http.toBlocking().retrieve(HttpRequest.GET("/product/PROD-001"), Product)
then:
product.id == 'PROD-001'
and:
product.name == 'Micronaut in Action'
and:
product.price == 29.99
}
def "should support 404 response"() {
when:
http.toBlocking().exchange(HttpRequest.GET("/product/PROD-009"))
then:
def e = thrown HttpClientResponseException
e.status == HttpStatus.NOT_FOUND
}
}
Less boilerplate code, and the same effect. We could even #Inject EmbeddedServer embeddedServer if would like to access it, but there is no need to do so.

Unit testing JAX-RS/Jersey servlet with Guice Injections

I have an application that uses Jersey/JAX-RS for web services (annotations, etc) and Guice to inject service implementations. I don't really like the way Guice works with servlets directly, I prefer the Jersey way, so I had to do a bit of fussing to get the service injections to work since Guice wouldn't be creating my servlet classes, and I didn't want to deal with the HK2-Guice bridge. I did this by creating a listener class (called Configuration) that sets up the injectors in static fields upon application startup and then manually effecting the injections in each servlet class by creating a parent class that all my servlets extend with a constructor that contains the following:
public MasterServlet() {
// in order for the Guice #Inject annotation to work, we have to create a constructor
// like this and call injectMembers(this) on all our injectors in it
Configuration.getMyServiceInjector().injectMembers(this);
Configuration.getDriverInjector().injectMembers(this);
}
I know it's kind of hacky, but this works just fine in my servlets. I can use the Guice #Inject annotations on my services and switch between named implementations and so on. The problem comes when I go to set up my unit tests. I'm using JerseyTest to do my tests, but running a test against my servlets results in a 500 error with Guice saying the following:
com.google.inject.ConfigurationException: Guice configuration errors:
1) No implementation for com.mycompany.MyService was bound.
while locating com.mycompany.MyService
for field at com.mycompany.servlet.TestGetServlet.service(TestGetServlet.java:21)
while locating com.mycompany.servlet.TestGetServlet
The test looks like this:
public class TestServletTest extends JerseyTest {
#Test
public void testServletFunctional() {
final String response = target("/testget").request().get(String.class);
assertEquals("get servlet functional", response);
}
#Before
public void setup() {
Configuration configuration = new Configuration();
configuration.contextInitialized(null);
}
#Override
protected Application configure() {
return new ResourceConfig(TestGetServlet.class);
}
}
You'll notice in the setup method I am manually creating my Configuration class since I can't rely on the test container (Grizzly) to create it (I get NullPointerExceptions without those two lines). More about this below.
And here's the servlet being tested:
#Path("/testget")
public class TestGetServlet extends MasterServlet {
#Inject
MyService service;
#GET
#Produces({"text/plain", MediaType.TEXT_PLAIN})
public String testGet() {
//service = Configuration.getServiceInjector().getInstance(MyService.class);
return "get servlet functional";
}
}
Notice the commented line in the testGet() method? If I do that instead and remove the #Inject annotation above, everything works fine, which indicates that Grizzly is not creating my servlets the way I expect.
I think what's happening is that Grizzly doesn't know about Guice. Everything seems to suggest that Grizzly isn't seeing the Configuration class, despite the fact that by putting it in my test's #Before method it seems to be at least available to the classes that use it (see: the commented line in the TestGetServlet class). I just don't know how to fix it.
I'm still trying to figure this out but in the meantime I switched from Guice to HK2, which took a bit of doing but I figured this might be helpful for anyone who runs into this problem in the future.
I consider this an answer because truthfully my attempt to bypass the Guice-HK2 bridge but still use Guice with Jersey might not have been the best idea.
Switching from Guice to HK2 takes a bit of doing and there's no comprehensive guide out there with all the answers. The dependencies are really fussy, for example. If you try to use Jersey 2.27 you may run into the famous
java.lang.IllegalStateException: InjectionManagerFactory not found
error. Jersey 2.27 is not backwards compatible with previous versions due to HK2 itself. I am still working on getting that all to work, but in the meantime I had to downgrade all my Jersey dependencies to 2.26-b06 to get HK2 working properly.
Jersey thankfully already implements a bunch of HK2 boilerplate, so all you need to get injection working is proper use of #Contract, #Service (see HK2 docs for those), and then two new classes that look like this:
public class MyHK2Binder extends AbstractBinder {
#Override
protected void configure() {
// my service here is a singleton, yours might not be, so just omit the call to in()
// also, the order here is switched from Guice! very subtle!
bind(MyServiceImpl.class).to(MyService.class).in(Singleton.class);
}
}
And this:
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
register(new MyHK2Binder());
packages(true, "com.mycompany");
}
}
Simple enough, but this only works for the application itself. The test container knows nothing about it, so you have to redo the Binder and ResourceConfig yourself in your test class, like this:
public class TestServletTest extends JerseyTest {
#Test
public void testServletFunctional() {
final String response = target("/testget").request().get(String.class);
assertEquals("get servlet functional", response);
}
#Before
public void setup() {
}
#Override
protected Application configure() {
return new TestServletBinder(TestGetServlet.class);
}
public class TestServletBinder extends ResourceConfig {
public TestServletBinder(Class registeree) {
super(registeree);
register(new MyHK2Binder());
packages(true, "com.mycompany");
}
}
}
Having to do this is actually fine because you can switch out the Binder for a test binder instead, in which you've bound your service to a mocked service instead or something. I haven't done that here but that's easy enough to do: replace new MyHK2Binder() in the call to register() with one that does a binding like this instead:
bind(MyTestServiceImpl.class).to(MyService.class).in(Singleton.class);
And voila. Very nice. Obviously you could achieve a similar result with Named bindings, but this works great and might even be simpler and more clear.
Hope this helps someone save the hours I spent screwing around to get this working.

How to test output HTTP request content in Spring application?

I have the Spring application.
We have the service which makes HTTP requests to external services. Now I think about writing Unit Test on this functionality. I want to write the integration tests. Thus I want to know that service request is correct.
Is there ways to do it in spring? (actually I don't know ways to do it outside the Spring too)
In tests you can use some kind of mock server. Wiremock for example.
Wiremock can work as a proxy and log all your requests and responses. More than that - it can then save responses and use them as stubs. It can be very useful to test integration problems with number of fault simulations.
For spring boot there is a starter:
<dependency>
<groupId>com.epages</groupId>
<artifactId>wiremock-spring-boot-starter</artifactId>
<version>0.7.18</version>
<scope>test</scope>
</dependency>
More documentation available here: https://github.com/ePages-de/restdocs-wiremock
Then create a test and setup a proxy:
#RunWith(SpringRunner.class)
#EnableAutoConfiguration
#SpringBootTest(
classes = {
YourApplication.class,
}
)
#WireMockTest // it comes from starter
public class YourTest {
#Inject
private WireMockServer server;
#Value("http://localhost:${wiremock.port}")
private String uri;
#Test
public void shouldLogAllTheThings() throws Exception {
server.stubFor(get(urlMatching("/other/service/.*"))
.willReturn(
aResponse()
.proxiedFrom("http://otherhost.com/approot")
));
// your call with rest template using uri field value
// as base uri
}
#TestConfiguration
public static class Internal {
#Inject
public WireMockConfiguration configuration;
#PostConstruct
public void wiremock() {
// this adds verbosive logger
// which will print all communication
configuration.notifier(new Slf4jNotifier(true));
}
}
}
More info:
http://wiremock.org/docs/proxying/
Mappings can be saved using this doc: http://wiremock.org/docs/record-playback/
If you don't want to use starter, you can use wiremock as JUnit rule:
http://wiremock.org/docs/junit-rule/

How to mock remote REST API in unit test with Spring?

Assume I have made a simple client in my application that uses a remote web service that is exposing a RESTful API at some URI /foo/bar/{baz}. Now I wish to unit test my client that makes calls to this web service.
Ideally, in my tests, I’d like to mock the responses I get from the web service, given a specific request like /foo/bar/123 or /foo/bar/42. My client assumes the API is actually running somewhere, so I need a local "web service" to start running on http://localhost:9090/foo/bar for my tests.
I want my unit tests to be self-contained, similar to testing Spring controllers with the Spring MVC Test framework.
Some pseudo-code for a simple client, fetching numbers from the remote API:
// Initialization logic involving setting up mocking of remote API at
// http://localhost:9090/foo/bar
#Autowired
NumberClient numberClient // calls the API at http://localhost:9090/foo/bar
#Test
public void getNumber42() {
onRequest(mockAPI.get("/foo/bar/42")).thenRespond("{ \"number\" : 42 }");
assertEquals(42, numberClient.getNumber(42));
}
// ..
What are my alternatives using Spring?
Best method is to use WireMock.
Add the following dependencies:
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<version>2.4.1</version>
</dependency>
<dependency>
<groupId>org.igniterealtime.smack</groupId>
<artifactId>smack-core</artifactId>
<version>4.0.6</version>
</dependency>
Define and use the wiremock as shown below
#Rule
public WireMockRule wireMockRule = new WireMockRule(8089);
String response ="Hello world";
StubMapping responseValid = stubFor(get(urlEqualTo(url)).withHeader("Content-Type", equalTo("application/json"))
.willReturn(aResponse().withStatus(200)
.withHeader("Content-Type", "application/json").withBody(response)));
If you use Spring RestTemplate you can use MockRestServiceServer. An example can be found here REST Client Testing With MockRestServiceServer.
If you want to unit test your client, then you'd mock out the services that are making the REST API calls, i.e. with mockito - I assume you do have a service that is making those API calls for you, right?
If on the other hand you want to "mock out" the rest APIs in that there is some sort of server giving you responses, which would be more in line of integration testing, you could try one of the many framework out there like restito, rest-driver or betamax.
You can easily use Mockito to mock a REST API in Spring Boot.
Put a stubbed controller in your test tree:
#RestController
public class OtherApiHooks {
#PostMapping("/v1/something/{myUUID}")
public ResponseEntity<Void> handlePost(#PathVariable("myUUID") UUID myUUID ) {
assert (false); // this function is meant to be mocked, not called
return new ResponseEntity<Void>(HttpStatus.NOT_IMPLEMENTED);
}
}
Your client will need to call the API on localhost when running tests. This could be configured in src/test/resources/application.properties. If the test is using RANDOM_PORT, your client under test will need to find that value. This is a bit tricky, but the issue is addressed here: Spring Boot - How to get the running port
Configure your test class to use a WebEnvironment (a running server) and now your test can use Mockito in the standard way, returning ResponseEntity objects as needed:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class TestsWithMockedRestDependencies {
#MockBean private OtherApiHooks otherApiHooks;
#Test public void test1() {
Mockito.doReturn(new ResponseEntity<Void>(HttpStatus.ACCEPTED))
.when(otherApiHooks).handlePost(any());
clientFunctionUnderTest(UUID.randomUUID()); // calls REST API internally
Mockito.verify(otherApiHooks).handlePost(eq(id));
}
}
You can also use this for end-to-end testing of your entire microservice in an environment with the mock created above. One way to do this is to inject TestRestTemplate into your test class, and use that to call your REST API in place of clientFunctionUnderTest from the example.
#Autowired private TestRestTemplate restTemplate;
#LocalServerPort private int localPort; // you're gonna need this too
How this works
Because OtherApiHooks is a #RestController in the test tree, Spring Boot will automatically establish the specified REST service when running the SpringBootTest.WebEnvironment.
Mockito is used here to mock the controller class -- not the service as a whole. Therefore, there will be some server-side processing managed by Spring Boot before the mock is hit. This may include such things as deserializing (and validating) the path UUID shown in the example.
From what I can tell, this approach is robust for parallel test runs with IntelliJ and Maven.
What you are looking for is the support for Client-side REST Tests in the Spring MVC Test Framework.
Assuming your NumberClient uses Spring's RestTemplate, this aforementioned support is the way to go!
Hope this helps,
Sam
Here is a basic example on how to mock a Controller class with Mockito:
The Controller class:
#RestController
#RequestMapping("/users")
public class UsersController {
#Autowired
private UserService userService;
public Page<UserCollectionItemDto> getUsers(Pageable pageable) {
Page<UserProfile> page = userService.getAllUsers(pageable);
List<UserCollectionItemDto> items = mapper.asUserCollectionItems(page.getContent());
return new PageImpl<UserCollectionItemDto>(items, pageable, page.getTotalElements());
}
}
Configure the beans:
#Configuration
public class UserConfig {
#Bean
public UsersController usersController() {
return new UsersController();
}
#Bean
public UserService userService() {
return Mockito.mock(UserService.class);
}
}
The UserCollectionItemDto is a simple POJO and it represents what the API consumer sends to the server. The UserProfile is the main object used in the service layer (by the UserService class). This behaviour also implements the DTO pattern.
Finally, mockup the expected behaviour:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader = AnnotationConfigContextLoader.class)
#Import(UserConfig.class)
public class UsersControllerTest {
#Autowired
private UsersController usersController;
#Autowired
private UserService userService;
#Test
public void getAllUsers() {
initGetAllUsersRules();
PageRequest pageable = new PageRequest(0, 10);
Page<UserDto> page = usersController.getUsers(pageable);
assertTrue(page.getNumberOfElements() == 1);
}
private void initGetAllUsersRules() {
Page<UserProfile> page = initPage();
when(userService.getAllUsers(any(Pageable.class))).thenReturn(page);
}
private Page<UserProfile> initPage() {
PageRequest pageRequest = new PageRequest(0, 10);
PageImpl<UserProfile> page = new PageImpl<>(getUsersList(), pageRequest, 1);
return page;
}
private List<UserProfile> getUsersList() {
UserProfile userProfile = new UserProfile();
List<UserProfile> userProfiles = new ArrayList<>();
userProfiles.add(userProfile);
return userProfiles;
}
}
The idea is to use the pure Controller bean and mockup its members. In this example, we mocked the UserService.getUsers() object to contain a user and then validated whether the Controller would return the right number of users.
With the same logic you can test the Service and other levels of your application. This example uses the Controller-Service-Repository Pattern as well :)

Unit testing Jersey Resources with Guice injected fields

I have a Jersey Resource that I want to test with JUnit. The resource uses Guice Providers to inject certain fields:
#Path("/example/")
class ExampleResource {
#Inject
Provider<ExampleActionHandler> getMyExampleActionHandlerProvider;
#GET
#Produces(MediaType.APPLICATION_JSON)
public List<ExamplePojo> getExampleList() {
ExampleActionHandler handler = getMyExampleActionHandlerProvider.get();
handler.doSomething();
...
This all works beautifully when using a real server to serve the API, however testing it is problematic.
My test class currently looks something like:
public class ApiTest extends JerseyTest {
public ApiTest() throws Exception {
super();
ApplicationDescriptor appDescriptor = new ApplicationDescriptor();
appDescriptor.setContextPath("/api");
appDescriptor.setRootResourcePackageName("com.my.package.name");
super.setupTestEnvironment(appDescriptor);
}
#Test
public void testHelloWorld() throws Exception {
String responseMsg = webResource.path("example/").get(String.class);
Assert.assertEquals("{}", responseMsg);
}
}
Clearly, Guice isn't getting the opportunity to initialize the fields in ExampleResource so that the handler.doSomething() call doesn't result in a NullPointerException.
Is there a way to tell Jersey to instantiate the ExampleResource class using Guice so that the Provider works?
One way to do it is to break the tests to few steps. You need to create the injector you're configuring the service with and test that injector (see Testing Guice Servlet bindings and Testing Guice can init servlets). Using these tests you make sure you have the right bindings in place.
Once you have the injector, get the ApplicationDescriptor object from it with
ExampleResource exampleResource = injector.getInstance(ExampleResource.class);
Assert.assertEquals(myList, getExampleList());

Categories