Mock Service inside resource using jersey test framwork - java

I have a resource for rest API which uses a service.
This service has a constructor with parameters.
I want to test this resource and to mock this service.
This Question: How to pass parameters to REST resource using Jersey 2.5
wasn't helpful because they used #Inject and I cannot use it.
Any suggestions?
The second question is how do I pass parameter to test this resouce:
My code is:
#Path("/2/{subversion: [0-3]}/users")
public class UserResource {
Logger log = Logger.getLogger(UserResource.class);
private MyService service;
public void setService(Service ser) {
this.service = ser;
}
#Context HttpServletRequest currentRequest;
#GET
#Produces("application/json")
public Response getUsers(#Context HttpHeaders httpHeaders, #Context UriInfo
uriInfo) {
// my function
}
}
How can I pass "httpHeaders" and "UriInfo".
My test looks like this:
Response response = target("/2/0/users/").request().get();
Users users = response.readEntity(Users.class);
assertNotNull(users);

For the service, it's good practice to either inject through the constructor or setter. This makes it easy to mock and pass in during unit testing. As for the mocking, you should use a framework like Mockito. Then you can do stuff like
MyService service = Mockito.mock(MyService.class);
when(service.getObject()).thenReturn(new Object());
HttpHeaders headers = Mockito.mock(HttpHeaders.class);
when(headers.getHeaderString("X-Header")).thenReturn("blah");
UriInfo uriInfo = Mockito.mock(UriInfo.class);
when(uriInfo.getRequestUri()).thenReturn(URI.create("http://localhost"));
Then you can just pass all these mocks to your resource class when UNIT testing.
For INTEGRATION testing you won't need to mock the headers or uriinfo. The actual ones will get passed in. But you can still mock the service if you want. Here's an example
public class MockServiceTest extends JerseyTest {
public static interface Service {
String getMessage(String name);
}
#Path("message")
public static class MessageResource {
private final Service service;
public MessageResource(Service service) {
this.service = service;
}
#GET
public String get(#QueryParam("name") String name,
#Context HttpHeaders headers,
#Context UriInfo uriInfo) {
String nameQuery = uriInfo.getQueryParameters().getFirst("name");
String header = headers.getHeaderString("X-Header");
assertNotNull(nameQuery);
assertNotNull(header);
return service.getMessage(name);
}
}
private Service service;
#Override
public ResourceConfig configure() {
service = Mockito.mock(Service.class);
return new ResourceConfig().register(new MessageResource(service));
}
#Test
public void testIt() {
Mockito.when(service.getMessage("peeskillet")).thenReturn("Hello peeskillet");
Response response = target("message").queryParam("name", "peeskillet").request()
.header("X-Header", "blah")
.get();
assertEquals(200, response.getStatus());
assertEquals("Hello peeskillet", response.readEntity(String.class));
}
}

Related

ClientRequestFilter get PathParameter

I have a JAX-RS rest client with following definition.
#PUT
#Path("/payments/{paymentId}/operation")
void call(#PathParam("paymentId") String paymentId, Object request);
I would like to intercept this outgoing request and read the paymentId value in a ClientRequestFilter.
#Provider
public class TracingInterceptor implements ClientRequestFilter {
public static final String PAYMENT_ID = "paymentId";
#Context
UriInfo info;
#Override
public void filter(ClientRequestContext requestContext) {
// read paymentId
}
}
I tried with UriInfo which works for ContainerRequestFilter but the context is not available in a ClientRequestFilter.
How can I read a specific path parameter in a ClientRequestFilter?
Use ClientRequestContext#getUri: https://docs.oracle.com/javaee/7/api/javax/ws/rs/client/ClientRequestContext.html#getUri.

How to embed request level objects to #Context

In embedded Jersey I can register a Binder to put in some resources that I can eventually access using #Context
However, those things I put in are more global and not on a per request level. I do know I can do it with some property mapping, but I would rather do it through #Context with class like Response foo(#Context HttpServletRequest)
I tried the setRequestScopedInitializer() but it does not put them in as expected and following their example with the Ref gives me a null pointer exception
Is there any way of doing this?
Here's how I eventually did it, but I don't like that I used a named property
RoutingContext was the type I wanted to inject
public class RoutingContextFactory implements
Supplier<RoutingContext> {
#Inject
private ContainerRequest request;
#Override
public RoutingContext get() {
return (RoutingContext) request.getProperty(RoutingContext.class.getName());
}
}
My binder
public class MyBinder extends AbstractBinder {
#Override
protected void configure() {
bindFactory(RoutingContextFactory.class)
.to(RoutingContext.class)
.proxy(true)
.proxyForSameScope(false)
.in(RequestScoped.class);
}
}
Initialized by
final ResourceConfig resourceConfig = ResourceConfig.forApplicationClass(applicationClass);
resourceConfig.register(new MyBinder());
Loaded by
final ContainerRequest request = new ContainerRequest(...
request.setProperty(RoutingContext.class.getName(), routingContext);
Used by
#GET
#Produces(MediaType.TEXT_PLAIN)
public String hello(
#Context final RoutingContext routingContext) {
return "Hello"
+ routingContext;
}
I still wish there was a way for me to just go request.register(routingContext). I opened up https://github.com/jersey/jersey/issues/3682 for this.

how to inject headers in a `#context HttpServletRequest`?

Let's say I have this code:
#ApplicationPath("...")
public class MyApp extends ResourceConfig {
public SalesLayerApplication() {
this.register(HeaderInjecterFilter.class);
this.register(Test.class);
}
}
#PreMatching
public class HeaderInjecterFilter implements ContainerRequestFilter {
#Override
public void filter(final ContainerRequestContext crc) throws IOException {
crc.getHeaders().add("foo", "bar");
}
}
#Path("/test")
public class Test {
#GET
#Produces(MediaType.TEXT_PLAIN)
public String dump(#Context final HttpServletRequest request) {
return request.getHeader("foo");
}
}
I was expecting to call the rest entry point /test and to retrieve the string bar.
But all I see is null
If I use #HeaderParam("foo") I correctly retrieve the variable, but I need to access throug the #Context HttpServletRequest.
Why would you expect that adding headers to the ContainerRequestContext would also add it to the HttpServletRequest? These are completely unrelated entities. Try injecting HttpHeaders or you can also inject the ContainerRequestContext directly.

How to test Rest API with Arquillian and Mock

I would like to test following class implements JAX-RS with CDI Injects inside.
#Path("area")
public class AreaService {
#Inject
#SuppressWarnings("unused")
private Logger logger;
#Context
private SecurityContext context;
#Inject
private AreaGateway areaGateway;
#GET
#Path("{area-name}/team-project/{tp-id}")
#Produces(MediaType.APPLICATION_JSON)
public Response getAreaByTeamProjectAndName(#PathParam("tp-id") long tpId, #PathParam("area-name") String areaName)
throws WebApplicationException {
Area area = areaGateway.getAreaByTeamProjectAndName(tpId, areaName);
return Response.status(Response.Status.OK).entity(area).build();
}
#POST
#Path("team-project/{tp-id}")
#Auditable
#Consumes(MediaType.APPLICATION_JSON)
public Response createArea(#PathParam("tp-id") long tpId, #Payload Area area) throws WebApplicationException {
long areaId = areaGateway.createArea(tpId, area, context);
return Response.status(Response.Status.CREATED).entity(areaId).build();
}
}
I have choosen Arquillian as test framework and I have used the extension for the REST APIs.
In particular i have tried to follow the Warp REST example, but i can't find a clean and clear sample to test my REST API with mocking inject dependency like AreaGateway with any mocking framework like Mockito.
I would like to do something like this:
#RunWith(Arquillian.class)
public class RestClientTestCase {
#ArquillianResource
public URL contextPath;
private AreaService areaService;
private AreaGateway areaGateway;
#Deployment(testable = false)
public static WebArchive create() {
WebArchive war = ShrinkWrap.create(WebArchive.class)
.addClasses(SLF4JProducer.class, AreaGateway.class, JAXRSActivator.class)
.addAsManifestResource(EmptyAsset.INSTANCE, "WEB-INF/beans.xml");
MavenResolverSystem resolver = Maven.resolver();
war.addAsLibraries(resolver.loadPomFromFile("pom.xml").resolve("org.mockito:mockito-all:1.10.8").withTransitivity().asSingleFile());
return war;
}
#BeforeClass
public static void setUpClass() {
// initializes the rest easy client framework
RegisterBuiltin.register(ResteasyProviderFactory.getInstance());
}
#Before
public void setUp() {
areaGateway = Mockito.mock(AreaGateway.class);//real bean replaced by mocked one
Mockito.when(areaGateway.getAreaByTeamProjectAndName(0, "areaName")).thenReturn(new Area());
ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target("" + "rest");
areaService = target.proxy(AreaService.class);
}
#Test
#RunAsClient
public void testStockGetWarp() {
Response response = areaService.getAreaByTeamProject(0);
assertEquals("The service returned status code.", 201, response.getStatus());
response.close();
}
}
Could someone help me to develop minimal test sample with exact Maven dependencies? Is it possible to mock CDI dependency with some framework according to Arquillian?

Mock UriInfo is not working

I'm trying to setup a couple of unit tests but i'm stuck at this.
This is my service class:
#Component
#Scope("request")
#Path("/subscriber/{accNo}/case/")
public class ServiceRest {
#Context
private UriInfo uriInfo;
#Autowired
private ActivationCase actCase;
#POST
#Path("activation")
public Response activate(#PathParam("accNo") String accNo, InputStream jSonInput) {
Integer order = actCase.activateMethod(accNo);
Link link = new Link("order", uriInfo.getBaseUriBuilder().path(OrderRest.class).path("" + order).build().toString(), "GET");
}
}
This is my Test Class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "/myapp-context.xml" })
#WebAppConfiguration
#Ignore
public class ServiceRestTest{
#Autowired
private ServiceRest restClient;
#Autowired
protected OrderServiceImpl orderService;
#Test()
public void testActivationCaseOK() {
UriInfo uriInfo = Mockito.mock(UriInfo.class);
UriBuilder uriBuilder = Mockito.mock(UriBuilder.class);
Mockito.when(uriInfo.getBaseUriBuilder()).thenReturn(uriBuilder);
Mockito.when(orderService.readThings(Mockito.any(Acct.class))).
thenReturn(stuff);
Mockito.when(orderService.maintainPlan(Mockito.any(Order.class))).
thenReturn(stuff2);
Response response = restClient.activateMethod("111111114");
}
Can anyone explain me why is uriInfo NULL?
The mock is done, it should have returned my URIBuilder no?
Thanks for you help
Unfortunately none of suggestions worked for me :/
I have to do a workaround.
So , in order to make this work i moved the #Context private UriInfo uriInfo to be a parameter in each method.
public Response activate(#PathParam("accNo") String accNo, InputStream jSonInput, #Context UriInfo) {
And in my unit test:
Mockito.when(uriInfo.getBaseUriBuilder()).thenReturn(uriBuilder);
Mockito.when(uriBuilder.path(Mockito.anyString())).thenReturn(uriBuilder);
Mockito.when(uriBuilder.build()).thenReturn(uri);
Response response = restClient.activateMethod("111111114", uriInfo);
Thanks for your feedback. I hope this can help somebody in the future
Try adding this code
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
(If it's still null then consider changing the Mockito.mock() to #Mock annotations as described here: http://solutiondesign.com/blog/-/blogs/spring-and-mockito-happy-together )

Categories