Class Permission implements ContainerRequestContext
{
#context
HttpServletRequest servletRequest;
public void filter(ContainerRequestContext containerRequestContext) throws IOException
{
String Path=servletRequest.getPathInfo;
int id=containerRequestContext.getId;
if(id==null){
containerRequestContext.abortWith(new ServerResponse(ExceptionUtil.getErrorMessageObject(...),errorCode,new Header<Object>()));
}
}
}
For the Testing purpose,
How to fetch the errorCode set inside the ServerResponse object when we are setting the id=null.
#RunWith(MockitoJUnitRunner.class)
class Test {
#InjectMocks
private Permission permission;
#Mock
private HttpServletRequest servletRequest;
#Mock
private ContainerRequestContext containerRequestContext;
#Test
public void test()
{
when(servletRequest.getPathInfo()).thenReturn("/getid");
when(containerRequestContext.getId()).thenReturn(null);
permission.filter(containerRequestContext);
Response r = //Need the code. How to get the Response that i have set on permission class when id=null so that i can fetch the errorCode from that.
//With that erroCode i can write my test methods.
}
}
What you need is an ArgumentCaptor:
ArgumentCaptor<Response> argumentCaptor = ArgumentCaptor.forClass(Response.class);
verify(containerRequestContext).abortWith( argumentCaptor.capture() );
This checks if the method abortWith has been called exactly once (once being the default for verify) and stores the argument it has been called with in the ArgumentCaptor from which you can get it via...
Response response = argumentCaptor.getValue();
For further details see the JavaDoc.
Of course, there are other ways (for example, you could use an Answer) but they are not as easy.
Related
I am using Mockito for Testing Filter,I am trying to test do filter chain method which requires HTTPServlet request as parameter, I tried mocking both Servlet Request and HTTPServlet Request but I am receiving
errors,
when using HTTPServlet request as null pointer exception, & with
Servlet Request as it cannot be cast. Any leads is appreciated.
My Filter looks like,
public class CheckerFilter implements Filter {
private final UserDetails userDetails;
priate final UserAuthentication userAuthentication
public CheckerFilter(UserDetails userDetails,UserAuthentication userAuthentication ){
this.userDetails = userDetails;
this.userAuthentication = userAuthentication;
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException{
final HttpServletRequest request = (HttpServletRequest)req;
final String method = request.getMethod();
final String contentType = request.getContentType();
boolean result = evaluate();
....
if(result)filter.doChain(request, res, chain);
else res.sendRedirect('\XXX');
}
}
Test looks like,
public class CheckerFilterTest {
#InjectMocks private CheckerFilter checkerFilter;
final UserDetails userDetails =mock(UserDetails.class);
final UserAuthentication userAuthentication = mock (UserAuthentication.class);
#Mock ServletRequest mockServeletRequest;
#Mock ServletResponse mockResponse;
#Mock HTTPServeltRequest mockHttprequest;
public void setUp (){
checkerFilter = new CheckerFilter(userDetails, userAuthentication);
}
#Test
public void Evaluate_returnsTrue(){
when(evaluate()).thenReturn(true);
checkerFilter.doFilter(mockHTTPrequest, mockResponse, mockchain);
//Error denoting mockHTTPRequest as null pointer exception.
//checkerFilter.doFilter(mockServletrequest, mockResponse, mockchain);Error mentioning Servlet Request cannot be cast to HTTPServlet Request.
}
}
The mocks need to be initialised. You can use MockitoAnnotations.initMocks(this) in the setup() method to initialise the #Mock annotated mocks. Also you have to use the http servlet request mock and not a servlet request mock as it cannot be downcasted
I have a service class that calls a REST API to get, create, update and delete subscribers. The Uri remains the same, but the HTTP method changes as you'd expect. I want to test the correct method is given. Below is an example of the updateSubscriber and its test.
public class MyService {
HttpClient httpClient;
public MyService(HttpClient httpClient) {
this.httpClient = httpClient;
}
//...
public int updateSubscriber(Subscriber subscriber) throws ... {
// PUT is the correct method for this request
HttpResponse response = httpClient.execute( new HttpPut( "https://example.org/api/subscribers" ) );
//...
}
//...
Here is my test with JUnit and Mockito:
#RunWith(MockitoJUnitRunner.class)
public class MyServiceTest
{
#Mock
private HttpClient mockHttpClient;
#Mock
private HttpResponse mockResponse;
#Mock
private StatusLine mockStatusline;
#Mock
private HttpEntity mockEntity;
// test subject
private MyService myService;
#Before
public void setup() {
// // this will just ensure http* objects are returning our mocked instances so we can manipulate them..
// when(mockHttpClient.execute(any(HttpGet.class))).thenReturn(mockResponse);
// when(mockHttpClient.execute(any(HttpPost.class))).thenReturn(mockResponse);
// when(mockHttpClient.execute(any(HttpPut.class))).thenReturn(mockResponse);
// when(mockHttpClient.execute(any(HttpDelete.class))).thenReturn(mockResponse);
// when(mockResponse.getStatusLine()).thenReturn(mockStatusline);
// when(mockStatusline.getStatusCode()).thenReturn(HttpStatus.SC_OK);
myService = new MyService(mockHttpClient);
}
#Test
public void testUpdateSubscriber() throws ...
{
when(mockHttpClient.execute(any(HttpPut.class))).thenReturn(mockResponse);
when(mockResponse.getStatusLine()).thenReturn(mockStatusline);
when(mockStatusline.getStatusCode()).thenReturn(HttpStatus.SC_OK);
String responseString = "...";
// this is consumed by a static method which we cannot mock, so we must deal with an actual entity instance
BasicHttpEntity entity = new BasicHttpEntity();
entity.setContent(new ByteArrayInputStream(responseString.getBytes()));
when(mockResponse.getEntity()).thenReturn(entity);
// create a test case Subscriber instance
Subscriber subscriber = new Subscriber();
int statusCode = myService.updateSubscriber(subscriber);
assertEquals(HttpStatus.SC_OK, statusCode);
// just confirm that an HTTP request was made
// TODO this isn't working, still passes when wrong Http* method used
verify(mockHttpClient, times(1)).execute(any(HttpPut.class));
}
//...
However, when I (wrongfully) have the another Http* method instance, it still passes:
// this is wrong, and should fail, but passed :(
HttpResponse response = httpClient.execute( new HttpGet( "https://example.org/api/subscribers" ) );
I'd really like to be able to test this as the action performed could be wrong if the method is mistaken. This test is to ensure that the PUT method was correctly used with the HTTP request for updateSubscriber. Any ideas?
Test passes because HtppPut and HttpGet both are implementation classes of HttpRequestBase, Change the mocking from HttpRequestBase class to HttpPut class
when(mockHttpClient.execute(any(HttpPut.class))).thenReturn(mockResponse);
So now if you try with GET call Test will fail with NullPointerException since GET call has no stub
Not sure if this is the proper answer to my question but I got managed to get the tests to work as intended using a custom argument matcher:
package uk.ac.strath.matchers;
import org.apache.http.client.methods.HttpUriRequest;
import org.mockito.ArgumentMatcher;
public class HttpMethodMatcher implements ArgumentMatcher<HttpUriRequest> {
private String expectedClassName;
// constructors
public HttpMethodMatcher(String expectedClassName) {
this.expectedClassName = expectedClassName;
}
#Override
public boolean matches(HttpUriRequest httpMessage) {
if (httpMessage.getClass().getName().equals(expectedClassName)) {
return true;
}
return false;
}
}
Now in my test, I can do:
verify(mockHttpClient, times(1)).execute( argThat(new HttpMethodMatcher( HttpGet.class.getName() )) );
This tutorial was helpful: https://www.baeldung.com/mockito-argument-matchers
I would like to have a variable that follows along the full lifecycle of a request in java EE.
For example it could be for a logging function, so that I can filter all log entries by request.
The key part that I want to get at is that it must be relatively easy to implement in an already existing application so if possible some sort of dependency injection that gets the variable related to the specific request.
I've tried injectiong a #RequestScoped variable, but it doesn't work since it is only scoped to the container. I would need to be able to inject the same object to different containers. Is this at all possible?
EDIT: I want something along the lines of this:
#RequestScoped
public class RequestVariables {
public String id;
}
#Stateless
public class Logger {
#Inject
private RequestVariables requestVariables;
public void log(String message) {
System.out.println(requestVariables.id + ":" + message);
}
}
#Stateless
public class Service {
#Inject
private Logger logger;
#Inject
private RequestVariables requestVariables;
public void save(String data) {
logger.log("Save");
session.save(data + requestVariables.id); //Maybe add request parameter to save aswell
}
}
public class API {
#Inject
private Service service;
#Inject
private Logger logger;
#Inject
private RequestVariables requestVariables;
#Path("/1")
#GET
public Response get(#QueryParam("data") String data) {
requestVariables.id = UUID.randomUUID().toString()
service.save(data);
logger.log("Get");
return Response.status(204).build();
}
}
Currently this is what I have experimented with:
#RequestScoped
public class RequestScope {
private int test = 0;
public RequestScope(int test) {
this.test = test;
}
public RequestScope(){}
public int getTest() {
return test;
}
public void setTest(int test) {
this.test = test;
}
}
#Provider
public class RequestScopeFilter implements ContainerRequestFilter {
#Inject
private javax.inject.Provider<RequestScope> requestScopeProvider;
#Context
private HttpServletRequest request;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
requestScopeProvider.get().setTest(42);
request.setAttribute("test", "superTest");
}
}
#Stateless
#TransactionManagement(TransactionManagementType.BEAN)
#TransactionAttribute(value=TransactionAttributeType.NOT_SUPPORTED)
public class Service {
#Context
private HttpServletRequest httpServletRequest;
#Inject
private Provider<RequestScope> requestScopeProvider;
public void test() {
RequestScope scope = requestScopeProvider.get();
String test = (String)httpServletRequest.getAttribute("test");
}
}
So when I get the scope from my service then it is a new object with test set to 0, and then it throws an NPE since httpServletRequest is null
option #1
Implement an Interceptor and set the request id as HttpServletRequest attribute:
#AroundInvoke
public Object setRequestId(InvocationContext ic) throws Exception {
HttpServletRequest request = [..] // getHttpServletRequest(ic);
request.setAttribute("request-id", UUID.randomUUID().toString());
return ic.proceed();
}
Then use HttpServletRequest everywhere you need it
#Context
private HttpServletRequest httpRequest;
option #2
If want just to filter your logs by an unique id, you can configure your Logger to print the thread name: [%t]
Example: Log4j PatternLayout
option #3
Use a custom java bean to encapsulate the request data (query param, request id etc.) and pass this bean across your application services.
public class API {
#Inject
private Service service;
#Path("/1")
#GET
public Response get(MyCustomRequestBean data) {
service.doSomejob(data);
return Response.status(204).build();
}
}
Set the request id and query param in ParamConverter:
Jax-RS ParamConverter - ParamConverterProvider method return type mismatch
You can inject a provider in your service:
#Inject
Provider<RequestVariables> vars
And then call get () to get the instance. If you try to get () in a thread outside a request scope context you'll get an exception. I would however try to structure in a way that would not allow this to happen
A solution that I found is to use ThreadLocal variables. It seems rather dirty, but it works since each request is executed on it's own thread(as far as I am aware). So this is what I got:
public class RequestScope {
private static final ThreadLocal<String> id = ThreadLocal.withInitial(() -> UUID.randomUUID().toString());
public static String get() {
return id.get();
}
}
With that I can also easily exchange the ThreadLocal to return something more specific if so desired.
And I can get the variables from pretty much anywhere, assuming that the request is not starting a different thread
I'm trying to create test cases for a webservice but I'm getting nullpointerexception. This is the web service:
#Path("friendservice")
public class FriendWebService {
private static final Logger logger = Logger.getLogger(FriendWebService.class);
#EJB
private FriendRequestServiceInterface friendRequestService;
#GET
#Path("friendrequest")
#Produces(MediaType.TEXT_PLAIN)
public String createFriendRequest(
#Context HttpServletRequest request) {
logger.info("createFriendRequest called");
String result = "false";
User user = (User) request.getSession().getAttribute("user");
User otherUser = (User) request.getSession().getAttribute("profileuser");
if ((user != null) && (otherUser != null)) {
logger.info("Got two users from session, creating friend request.");
if (friendRequestService.createFriendRequest(user, otherUser)) {
result = "true";
}
}
return result;
}
}
This is my test class:
public class FriendWebServiceTest {
#Mock
FriendRequestServiceInterface FriendRequestService;
#Mock
Logger mockedLogger = mock(Logger.class);
#Mock
HttpServletRequest mockedRequest = mock(HttpServletRequest.class);
#Mock
HttpSession mockedSession = mock(HttpSession.class);
#Mock
User mockedUser = mock(User.class);
#Mock
User mockedOtherUser = mock(User.class);
#InjectMocks
FriendWebService friendWebService = new FriendWebService();
#Before
public void setUp() throws Exception {
}
#Test
public void testCreateFriendRequest() throws Exception {
when(mockedRequest.getSession()).thenReturn(mockedSession);
when(mockedSession.getAttribute("user")).thenReturn(mockedUser);
when(mockedSession.getAttribute("profileuser")).thenReturn(mockedOtherUser);
when(FriendRequestService.createFriendRequest(mockedUser, mockedOtherUser)).thenReturn(true);
assertTrue(friendWebService.createFriendRequest(mockedRequest) == "true");
}
The NullPointerException occurs at "when(FriendRequestService.createFriendRequest(mockedUser, mockedOtherUser)).thenReturn(true);"
What am I doing wrong?
You are chaining method calls on your mocked instance:
#Mock
HttpServletRequest mockedRequest = mock(HttpServletRequest.class);
First of all, you do not need to do both, either use the #Mock annotation or the mock method. Like this, you first assign a Mock and then replace this instance with another mock. I recommend the annotation as it adds some context to the mock such as the field's name. This might already cause your NullPointerException as you however never activate the annotations by calling:
MockitoAnnotations.initMocks(this);
as you do not consequently mock all instances with both measures so far. However, even doing so will further result in your exception, so let's move ahead.
Within friendWebService.createFriendRequest(mockedRequest) you call:
User user = (User) request.getSession().getAttribute("user");
User otherUser = (User) request.getSession().getAttribute("profileuser");
where you call a method on two mocks for which you did not specify any behavior. These mocks do by default return null. You need to specify behavior for this such as:
when(request.getSession()).thenReturn(myMockedSession);
before performing this chained call. Based on this, you can then specify how to react to calls on this mocked instance such as returning your user mocks.
Instead of calling initMocks, You probably need to annotate with #RunWith(MockitoJUnitRunner.class) to your FriendWebServiceTest class.
You can also try adding #RunWith(MockitoJUnitRunner.class) or #ExtendWith(MockitoExtension.class) annotations to your FriendWebServiceTest class for JUnit4 and JUnit5 respectively.
In my RPCServlet I am using the method AbstractRemoteServiceServlet.getThreadLocalRequest() to get the HttpSession. Now I want to unit-test it. I am using Mockito and thought I just could mock everything, but the method is final and protected.
Is there any other way to Unit-test AbstractRemoteServiceServlet.getThreadLocalRequest().getSession()
At the end you are trying to get a Session. In our case we solve this situation doing this:
Using GUICE for getting our instances (making them available in the GIVEN part of the test)
public class TestServerModule extends com.google.inject.AbstractModule {
#Override
protected void configure() {
.....
bind(HttpServletRequest.class).to(MockRequest.class).in(Singleton.class);
bind(HttpServletResponse.class).to(MockResponse.class).in(Singleton.class);
....
}
....
#Provides
#Singleton
RequestUtil getRequestUtil(final HttpServletRequest req, final HttpServletResponse resp) {
return new RequestUtilsImpl() {
public HttpServletRequest getThreadRequest() {
return req;
}
public HttpServletResponse getThreadResponse() {
return resp;
}
};
}
RequestUitl object contains everything related with Session and more server stuff (that is not important for your problem :D). The important part here is you can have access to the getThreadRequest(), so you have access to getSession() method.
What is the problem? You can not have a real HttpServletRequest object in your instances, so you need to mock them. For doing it, we specified the bind rules at the top.
At the end your test should be something like:
#RunWith(...)
#GuiceModules({TestServerModule.class, ....})
public class YourTest extends junit.framework.TestCase {
#Inject RequestUtil requestUtil;
....
#Test public void
test_session_after_doing_something() {
//GIVEN
HttpSession mockedSession = requestUtil.getThreadRequest().getSession();
....
}
....
}