How do I test business logic in a servlet using Junit? - java

I'm having a servlet that does some pre-condition checks before invoking a DAO method, like following:
private void processRequest(HttpServletRequest request, HttpServletResponse response){
if(a condition is met)
myDAOFunction();
else
redirect();
}
How should I construct my unit test to verify whether with a certain request, the servlet invokes my function, and with other requests that does not meet the condition then it will redirect the page?
I have tried this solution: Since my DAO function would make some changes in the database if it were called, and through that I can test if the servlet handles the requests and responses correctly. But I figure that is not quite an elegant solution.

So what you need to verify if the servlet can interact with the DAO related codes correctly. If your design already separate and encapsulate all the codes related to interacting with DB in a DAO service class , you can easily test it by mocking this DAO service class using Mockito and then verify if the expected methods on the mock DAO service are invoked with the expected parameters. If not , please refractor your codes such that it will have this separate DAO service class.
For mocking MockHttpServletRequest and MockHttpServletResponse , spring-test already provides some utilities to create them which are useful for testing the Servlet stuff. Although they are primarily designed to work with the codes written by spring-mvc , it should also be used for the codes that are not written by spring and should be more convenient to use when compared Mockito.
Assuming your servlet is called FooBarServlet, the test case may look like :
#ExtendWith(MockitoExtension.class)
public class FooBarServletTest {
#Mock
DaoService daoService;
#Test
void testSaveToDatabase(){
FooBarServlet sut = new FooBarServlet(daoService);
MockHttpServletRequest request = MockMvcRequestBuilders.get("/foobar")
......
.buildRequest(new MockServletContext());
MockHttpServletResponse response = new MockHttpServletResponse();
sut.processRequest(request, response);
verify(daoService).save("xxxxxx");
}
#Test
void testRedirect(){
FooBarServlet sut = new FooBarServlet(daoService);
MockHttpServletRequest request = MockMvcRequestBuilders.get("/foobar")
......
.buildRequest(new MockServletContext());
MockHttpServletResponse response = new MockHttpServletResponse();
sut.processRequest(request, response);
verify(daoService,never()).save(any());
}
}

Related

Ways to do picocontainer DI with REST assured request and response

I am building a rest assured test FW with picocontainer DI using cucumber java. I need to share the request and response using the DI, but REST assured provides RequestSpecification and Response which are Interfaces and Interfaces cannot be shared. What is the REST assured non interface class that will allow me to build a request and response, issue a HTTP request and read the request and response data in other classes. Basically I need a way to create rest assured request and response java object.
The dependency injection context in cucumber-jvm spans the execution of a scenario. So it can only contain objects which can be created without any information from the scenario.
So rather then trying to share the RequestSpecification and Response you can share a helper class that has references to these objects. For example (constructors ommited):
class MyStepDefs {
SomeService service;
#Given("a request")
void given_a_request(){
service.createRequest();
}
}
class OtherStepDefs {
SomeService service;
#When("a thing")
void a_thing(){
service.doThing();
}
}
class YetOtherStepDefs {
SomeService service;
#Then("it happens")
void a_thing(){
service.asserItHappend();
}
}

How to test only specific http request method available for controller method in Spring MVC?

I need to check if only specific http method is available for some url.
For example, if there is a controller like this
#Controller
public class FooController {
#RequestMapping(value = "bar", method = RequestMethod.GET)
public void bar() {/*do something*/};
...
}
For controller test I use junit(4.10), spring-test(3.2.10) and easymock(3.1).
If I write test like this
#Test
public void testBar() throws Exception {
mockMvc.perform(post("bar").session(session))
.andExpect(/*some application's default error response*/);
}
it will pass (although test calls post-method, not get-method).
So I'm looking for a proper way to make sure, that my rest resources are only avaiable by request methods specified in documentation. Two solutions came to my mind:
write tests with wrong request methods and somehow check resource is not available
add custom exception resolver to process org.springframework.web.HttpRequestMethodNotSupportedException: Request method '__' not supported and return same application default error response, but with https status 405 Method not allowed.
What would you suggest and how to check in controller test request method?
Thanks in advance.
You would need to check the status of all the request methods, you could do it using andExpect with status().isMethodNotAllowed() or status().isNotFound() depends on your needs:
Examples:
get: mockMvc.perform(get("bar").andExpect(status().isNotFound()) or mockMvc.perform(get("bar").andExpect(status().isMethodNotAllowed())
Do the same same for put, delete, ....

Mocking a REST call with MockRestServiceServer

I'm trying to write a JUnit test case which tests a method in a helper class. The method calls an external application using REST and it's this call that I am trying to mock in the JUnit test.
The helper method makes the REST call using Spring's RestTemplate.
In my test, I create a mock REST server and mock REST template and instanitiate them like this:
#Before
public void setUp() throws Exception {
mockServer = MockRestServiceServer.createServer(helperClass.getRestTemplate());
}
I then seed the mock server so that it should return an appropriate response when the helper method makes the REST call:
// response is some XML in a String
mockServer
.expect(MockRestRequestMatchers.requestTo(new URI(myURL)))
.andExpect(MockRestRequestMatchers.method(HttpMethod.GET))
.andRespond(MockRestResponseCreators.withStatus(HttpStatus.OK)
.contentType(MediaType.APPLICATION_XML)
.body(response));
When I run my test, the helper method receives a null response from the REST call it makes and the test fails.
The REST URL that the helper makes has query params and looks like this: "http://server:port/application/resource?queryparam1=value1&queryparam2=value2".
I've tried putting the URL ("http://server:port/application/resource") both with and without the query parameters in the "myURL" variable (to elicit a match so that it returns a response), but can not get the mock server to return anything.
I've tried searching for examples of this kind of code but have yet to find anything which seems to resemble my scenario.
Spring version 4.1.7.
Thanks in advance for any assistance.
When you create an instance of MockRestServiceServer you should use existing instance of RestTemplate that is being used by your production code. So try to inject RestTemplate into your test and use it when invoking MockRestServiceServer.createServer - don't create new RestTemplate in your tests.
Seems that you are trying to test the rest-client, the rest-server should be tested in other place.
You are using RestTemplate -> To call the service. Then, tried to mock RestTemplate and its call's results.
#Mock
RestTemplate restTemplateMock;
and Service Under Test Class
#InjectMocks
Service service;
Let say, Service has a method to be test as
public void filterData() {
MyResponseModel response = restTemplate.getForObject(serviceURL, MyResponseModel.class);
// further processing with response
}
Then, to test filterData method, you need to mock the response from restTemplate call such as
mockResponseModel = createMockResponse();
Mockito.when(restTemplateMock.getForObject(serviceURL, MyResponseModel.class)).thenReturn(mockResponseModel);
service.filterData();
//Other assert/verify,... go here
You can create a new instance of RestTemplate however you have to pass it in your createServer method like this:
private RestTemplate restTemplate = new RestTemplate();
#BeforeEach
public void setUp() {
MockitoAnnotations.initMocks(this);
mockServer = MockRestServiceServer.createServer(restTemplate);
client.setRestTemplate(restTemplate);
}

Obtaining actual parameter values in a Jersey ResourceFilterFactory

I want to implement custom authorisation in my REST services using Jersey. This custom authorisation inspects annotations on methods as well as the actual parameters that a
method receives.
My jax-rs annotated method looks like:
#GET
#Path("customers")
#Requires(Role.CustomerManager)
public Customer getCustomer(#ParseFromQueryString #CheckPermission final Customer customer) {
// ...
}
The #ParseFromQueryString is an annotation that indicates Jersey (through an Injectable provider) to unmarshall a Customer from a query string. The code for that looks like:
public class QueryStringCustomerInjectable implements Injectable<Customer> {
public Customer getValue() {
final Customer customer = new Customer();
// ... a UriInfo was injected using the #Context annotation
// ... extract parameters from QueryString and use setters
return customer;
}
}
The #CheckPermission annotation indicates my custom authoriser that permissions are to be checked on a customer. Some users have access to information on some customers. Similarly, the #Requires annotation takes a role that the invoker should have. These are not java's security roles (Strings), rather, they are enum values.
Using Jersey's ResourceDebuggingFilter as a starting point, I have been able to get to the point of knowing which method will be invoked. However, I still haven't figured out how to determine which parameters will actually be used to invoke the method.
At the top of my head, I can think of two work arounds:
A Method interceptor using Guice + Jersey.
Code this logic in the QueryStringCustomerInjectable, but this seems a bit sloppy. It would be a class doing too much.
Yet, I would really like to do this using only Jersey / JAX-RS. I feel that I am so close!
Ideas? Pointers?
Thanks!
You should use Filters or Interceptors to handle all the information about method.
see Jersey Filter and Interceptors
For the Customer deserialization you could implement the javax.ws.rs.ext.ParamConverterProvider and register it into Jersey. Then you can inject it into your methods with #QueryParam("customer"). It's a bit more flexible since you can use it also with #BeanParam or #PathParam annotations.
Then you can use the ContainerRequestFilter. See as a reference how jersey does the Oauth1 for example OAuth1ServerFilter.
The next thing you can do is to create maybe a feature which will register the newly created filter (see Oauth1ServerFeature for a reference - I couldn't find the source code right now).
Good luck!
Why not using your own Servlet filter e.g.
public class YourFilter implements Filter {
...
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
// HttpServletRequest httpReq = (HttpServletRequest) request;
// HttpServletResponse httpResp = (HttpServletResponse) response;
// HttpServletRequest httpReq = (HttpServletRequest) request;
// HttpServletResponse httpResp = (HttpServletResponse) response;
// ..... httpReq.getUserPrincipal();
// then set what you need using ThreadLocal and use it inside your resource class
// do not forget to call
filterChain.doFilter(request, response); // at the end of this method
}
The last step is to register your servlet filter. This is done using web app's web.xml
It will intercept your HTTP requests before the actual code inside jersey resource is called.

cache controller response

I'd like to use memcached to cache the response produced by my controllers. The controllers themselves are Grails controllers, but there's nothing really Grails-specific about the problem. If I could figure out how to solve this problem in a Spring MVC, Struts (or similar) application, I should easily be able to migrate the solution to Grails.
Ideally, I'd like to identify the controller methods that are eligible for caching using Java annotations. Is anyone aware of an existing solution for this problem? I should emphasise that I'm not interested in using any caching technology other than memcached.
Thanks,
Don
The Simple Spring Memcached library the previous poster linked to would actually accomplish what you need to do. It doesn't limit itself to just DAO methods. You could annotate a controller method to cache it's response just as easily as annotating a DAO method.
So, if you have a Controller named SimpleController and you wanted to cache the response of that controller, you could do the following
public class SimpleController implements Controller {
#ReadThroughSingleCache(namespace = "SimpleController", keyIndex = 0, expiration = 3600)
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
return new ModelAndView("index")
}
This will cache the response of the controller in Memcached for an hour and any request that comes in that matches the same request will return the cached response.
Aaron, braveterry,
Thanks for suggesting my project: http://code.google.com/p/simple-spring-memcached/
Don, Aaron is correct that SSM is not limited to DAO methods, however there are a few caveats for his example:
I don't think HttpServletRequest's toString() method would produce a good key
You would need to make sure that ModelAndView is Serializable
That being said, there's no reason you can't delegate to another bean that has an appropriate signature
Here's some code as an example:
public class SimpleController implements Controller {
private BeanWithAnnotatedMethod bean; // Injected resource
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
Object keyObject = Helper.generateAppropriateKey(request);
String result = bean.annotatedMethod(keyObject);
return new ModelAndView(result)
}
Would something like this do the trick? http://code.google.com/p/simple-spring-memcached/

Categories

Resources