Ways to do picocontainer DI with REST assured request and response - java

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();
}
}

Related

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

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());
}
}

Testing JSON mapping for a Spring Boot RestTemplate client

I have a REST API outside of my control (supplied by a different, distant team) which I need to consume from a Spring Boot application.
Currently I would like to write a test for that the request (not response) resulting from my RestTemplate invocation corresponds exactly to what is expected at the remote end. I have a sample JSON snippet that I would like to replicate from my code - given the same parameters as in the sample I should get an equivalent JSON snippet in the request body which I would then like to analyze to be certain.
My idea so far is to get RestTemplate to use a server under my control which then captures the JSON request. Apparently MockRestServiceServer is a good choice for this.
Is this the right approach? How do I configure MockRestServiceServer to allow me to do this?
If you're only interested in verifying the JSON mapping, you can always use Jackson's ObjectMapper directly and verify if the object structures match by using a library like JSONassert to verify if the serialized string matches your expected result. For example:
#Autowired
private ObjectMapper objectMapper;
private Resource expectedResult = new ClassPathResource("expected.json");
#Test
public void jsonMatches() {
Foo requestBody = new Foo();
String json = objectMapper.writeValueAsString(requestBody);
String expectedJson = Files
.lines(expectedResult.getFile())
.collect(Collectors.joining());
JSONAssert.assertEquals(expectedJson, json, JSONCompareMode.LENIENT);
}
This test purely uses ObjectMapper to verify the JSON mapping and nothing else, so you could even do this without actually having to bootstrap Spring boot within your test (which could be faster). The downside of this is that if you're using a different framework than Jackson, or if RestTemplate changes its implementation, that this test could become obsolete.
Alternatively, if you're interesting in verifying that the complete request matches (both URL, request method, request body and so on), you can use MockRestServiceServer as you mentioned. This can be done by adding the #SpringBootTest annotation to your test, autowiring RestTemplate and the service that invokes RestTemplate for example:
#RunWith(SpringRunner.class)
#SpringBootTest
public class FooServiceTests {
#Autowired
private RestTemplate restTemplate;
#Autowired
private FooService fooService; // Your service
private MockRestServiceServer server;
#Before
public void setUp() {
server = MockRestServiceServer.bindTo(restTemplate).build();
}
}
You can then set up your tests by using:
#Test
public void postUsesRestTemplate() throws IOException, URISyntaxException {
Path resource = Paths.get(getClass().getClassLoader().getResource("expected-foo.json").toURI());
String expectedJson = Files.lines(resource).collect(Collectors.joining());
server.expect(once(), requestTo("http://example.org/api/foo"))
.andExpect(method(HttpMethod.POST))
.andExpect(MockRestRequestMatchers.content().json(expectedJson))
.andRespond(withSuccess());
// Invoke your service here
fooService.post();
server.verify();
}
As per the documentation, you could match requests using json paths on Mock. For example;
RestTemplate restTemplate = new RestTemplate()
MockRestServiceServer server = MockRestServiceServer.bindTo(restTemplate).build();
server.expect(ExpectedCount.once(), requestTo(path))
.andExpect(method(HttpMethod.POST))
.andExpect(jsonPath("$", hasSize(1)))
.andExpect(jsonPath("$[0].someField").value("some value"))
Note: I haven't tested this.
But I have achieved what you are looking for using Wire Mock many times. That's again a much better option than MockRestServiceServer. Why do I say so?
wide adoption and support
more elegant and extensive request & response matching
highly configurable
record and playback
configurable security/auth
you could even dockerise this
Have a look at http://wiremock.org/docs/request-matching/
I think your approach using a stub server (you could use WireMock for this) is fine if you want to check once, manually.
Alternatively you could add a request logger to your RestTemplate which logs each request. That would make it easier to check if the sent request is correct any time if problems arise.

spring boot application with both front end and restful

I am Planning to build a web application using Spring Boot as restful service.
my spring boot web restful application should be accessible by other application as well. In case if any one accessing the rest service from other application then my application should work as expected.
#Controller
public class GreetingController {
#RequestMapping("/greeting")
public String greeting(#RequestParam(value="name", required=false, defaultValue="World") String name, Model model) {
model.addAttribute("name", name);
return "greeting";
}
}
In above example if call is made from outside of application then the rest service should return JSON output.
One way we can have some variable to distinguish as request variable. But I do not want like that. Please share some standard way.
Appreciate your help.
Idiomatic way is to rely on Accept request header.
If requester presents Accept: application/json then return him JSON data (REST API).
If requester provides you with Accept: application/xhtml+xml return him HTML (web frontend).
Implementation-wise you should is to be done use #RequestMapping with consumes argument. You need two methods. If business logic for both paths is the same then in could be reused. Business logic should reside in another method or in separate #Service. Business logic on its own should not know, care or rely on transport protocol (HTTP), serialization of request response or presentation. Business logic should just work with POJOs and leave serialization to #Controller.
#Controller
#RequestMapping("/greeting")
public class GreetingController {
#RequestMapping(consumes="application/json")
#ResponseBody //required if you want to return POJO (spring will serialize it to response body)
public void rest() {
//return POJO, it will be serialized to JSON. or serialize pojo
directly and return response with manually set body and headers.
}
#RequestMapping(consumes="application/xhtml+xml")
public void html() {
//populate model, return string pointing to HTML to View
}
}
I suggest creating two controller classes, the second one using #RestController. Then, have two paths; the second could be "rs/greeting". This approach, which separates the Web and RESTful concerns, is much more extensible and doesn't require any weird headers that most clients don't want to deal with.

How to intercept a request in Jersey using Annotations?

I'm using Jersey to build a REST API with your standard annotation based routing.
My question is, how can I use a "custom annotation" (in this case #InternalOnly) to intercept a request and run code before the request hits the resource and the // DO STUFF block is executed?
#Path("app")
#Produces(MediaType.APPLICATION_JSON)
public final class SomeResource {
#GET
#Path("something")
#InternalOnly
public Response getSomething() {
// DO STUFF
}
}
I would then have another class that would handle the #InternalOnly header...
public final class InternalOnlyHandler implements SomethingProbably {
public void handle(Object someContext) {
// HANDLE INTERNAL ONLY AUTHENTICATION
}
}
My purpose is basically I need certain API resources to be available internally ONLY and others publicly available and the Authentication is slightly different for both so registering a simple ContainerRequestFilter won't do the job.
I can't figure this out -- please help!

Jersey Async ContainerRequestFilter

I have a Jersey REST API and am using a ContainerRequestFilter to handle authorization. I'm also using #ManagedAsync on all endpoints so that my API can serve thousands of concurrent requests.
My authorization filter hits a remote service, but when the filter is run, Jersey hasn't yet added the current thread to it's internal ExecutorService, so I'm completely losing the async benefits.
Can I tell Jersey that I want this ContainerRequestFilter to be asynchronous?
#Priority(Priorities.AUTHORIZATION)
public class AuthorizationFilter implements ContainerRequestFilter
{
#Inject
private AuthorizationService authSvc;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException
{
String authToken = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
// HITS A REMOTE SERVER
AuthorizationResponse authResponse = authSvc.authorize(authToken);
if (!authResponse.isAuthorized())
{
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED)
.entity("unauthorized!")
.build());
}
}
}
And here's an example resource:
#Path("/stuff")
#Produces(MediaType.APPLICATION_JSON)
public class StuffResource
{
#GET
#Path("/{id}")
#ManagedAsync
public void getById(#PathParam("id") long id, #Suspended final AsyncResponse ar)
{
Stuff s;
// HIT THE DATABASE FOR STUFF
ar.resume(s);
}
}
UPDATE Just heard back from the Jersey guys, and this is not possible as of 2.7. Only the resource method itself is invoked asynchronously, not filters. Any suggestions for proceeding still welcome.
This is not built in to Jersey as of 2.7.
#ManagedAsync is useless if you have any filters or interceptors that do any serious work (like hit a remote authorization service). They may add the ability to run filters asynchronously in the future, but for now you're on your own.
UPDATE - there are other ways...
After a long and perilous journey, I have found a very hacky solution that I'm using in the short term. Here is a rundown of what I tried and why it failed/worked.
Guice AOP - failed
I use Guice for DI (getting Guice injection to work with Jersey is a feat in itself!), so I figured I could use Guice AOP to get around the issue. Though Guice injection works, it is impossible to get Guice to create resource classes with Jersey 2, so Guice AOP cannot work with resource class methods. If you are trying desperately to get Guice to create resource classes with Jersey 2, don't waste your time because it will not work. This is a well-known problem.
HK2 AOP - RECOMMENDED SOLUTION
HK2 just recently released an AOP feature, see this question for details on how to get it working.
Monitoring - also worked
This is not for the faint of heart, and it is completely discouraged in the Jersey docs. You can register and ApplicationEventListener and override onRequest to return a RequestEventListener that listens for RESOURCE_METHOD_START and calls an authentication/authorization service. This event is triggered from the #ManagedAsync thread, which is the whole goal here. One caveat, the abortWith method is a no-op, so this won't work quite like a normal ContainerRequestFilter. Instead, you can throw an exception if auth fails instead, and register an ExceptionMapper to handle your exception. If someone is bold enough to give this a try, let me know and I'll post code.
I am not sure if this is what you were looking for but, have you looked into Spring's OncePerRequestFilter? I am currently using it for my authorization layer where each request goes through some filter that extends this OncePerRequestFilter depending on how my filters are mapped to the URLs. Here's a quick overview of how I am using it:
Authentication/Authorization of a resource in Dropwizard
I am not very clear on the async dispatch parts of these filters but I hope this link atleast sheds some light to what you are trying to achieve!
We use Spring security for authentication/authorization. I worked around the problem using a sub-resource locator with empty path as shown below:
#Path("/customers")
public class CustomerResource {
#Inject
private CustomerService customerService;
#Path("")
public CustomerSubResource delegate() {
final Authentication auth = SecurityContextHolder.getContext().getAuthentication();
return new CustomerSubResource(auth);
}
public class CustomerSubResource {
private final Authentication auth;
public CustomerSubResource(final Authentication auth) {
this.auth = auth;
}
#POST
#Path("")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
#ManagedAsync
public void createCustomer(final Customer customer, #Suspended final AsyncResponse response) {
// Stash the Spring security context into the Jersey-managed thread
SecurityContextHolder.getContext().setAuthentication(this.auth);
// Invoke service method requiring pre-authorization
final Customer newCustomer = customerService.createCustomer(customer);
// Resume the response
response.resume(newCustomer);
}
}
}

Categories

Resources