I must write unit test using junit for a spring web project.
A controller have parameter like
#RequestMapping(value = "/tasks/{id}/", method = RequestMethod.PUT)
public ResponseEntity<String> unlock(
#PathVariable String id, #RequestPart String param)
I dont know what exactly param receive. I usually use #RequestPart MultipartFile.
In the test, Inject your class.
Add MockMvc (is a part of Spring Test an let you call your WS).
Prepare the mock, ie: when(myClassInjected.myMethod()).thenReturn(the_result);
Perform a call with MockMvc. (you can follow the tutorial at the end of the post)
Verify the call, ie: verify(myClassInjected, times(1)).myMethod();
Check this tutorial to get more information.
Related
I want to test the response of my request.
I have a controller like this,
#RequestMapping("/user")
public class StandardController(#RequestBody Object body) {
#PostMapping(path=/info")
public ResponseEntity<String> getUserInfo(#Validated #RequestBody CustomDTO customDTO) throws customException {
try {
//process something with customDTO
} catch (Exception e) {
//throw exception
}
}
}
Now I have made one of the properties of CustomDTO as #NotNull. When I test the endpoint through Postman I will successfully get 400 as expected if I supply the required field as null value. But how do I test this scenario with Mockito?
If you want to test Spring MVC controllers, don't use unit tests; you need to ensure that everything works correctly including mappings, validation, and serialization. Use MockMvc (in regular, not standalone mode), and if you like you can use Mockito to mock service dependencies.
If you want to test your controller, you have two categories of test:
Unit test by using spring test slice.
Integration test
Read this post also for more understanding.
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.
I have multiple links in my HTML, which are referring to URI in Controller Class,
How can I get this URI in some variable which can be used further, at last, I want to store these URI in DB.
HTML Code :
<td>Win Report</td>
<td>Win Report</td>
Spring Controller Class :
#RequestMapping(value = "/ui/report/win", method = RequestMethod.GET)
public String winReport() {
return "win_report";
}
#RequestMapping(value = "/ui/report/niw", method = RequestMethod.GET)
public String niwReport() {
return "niw_report";
}
You can use the below solution to retrieve the page Url as well as avoid using repetitive method calls.
You can use a Spring Boot HandlerInterceptor, here's a brief description of the same :
Handler interceptors are used when you want to apply specific
functionality to certain or all requests.
Handler Interceptors should implement the interface HandlerInterceptor. HandlerInterceptor can be used to avoid repetitive handler code.
We can use HandlerInterceptor for different purposes like authorization checks, locale checks, logging, creating common application parameters etc.
HandlerInterceptor works similar to the servlet filter. But in some cases filters are more powerful than HandlerInterceptor.
In Spring-MVC the HandlerInterceptor is configured in spring application context xml file or by Java configuration.
HandlerInterceptor has three methods.
preHandle( ) : It is executed before actual handler is executed.
postHandle( ) : It is executed after handler is executed.
afterCompletion( ) : It is executed after the complete request is finished.
For more details, you can use an example from the below link
https://www.tuturself.com/posts/view?menuId=3&postId=1071
You can get the entire sample project which can help you with the setup at
https://github.com/ninja-panda
To get the request url you can do the following:
#RequestMapping(value = "/ui/report/win", method = RequestMethod.GET)
public String winReport(HttpServletRequest request){
String request = request.getRequestURI();
// do somehting here
return "win_report"
}
Spring will automatically inject the HttpServletRequest.
Update:
If your want get the urls for all of your methods in your controller, you can go with RequestMappingHandlerMapping:
private final RequestMappingHandlerMapping handlerMapping;
#Autowired
public YourController(RequestMappingHandlerMapping handlerMapping) {
this.handlerMapping = handlerMapping;
}
With handlerMapping.getHandlerMethods(), you can access all mappings decleared in your controller. With reflection and getMappingAnnotation, you can then read the value of each RequestMapping annotation.
You can try the getServletPath() like following:
#RequestMapping(value = "/ui/report/win", method = RequestMethod.GET)
public String winReport(HttpServletRequest request){
String mapping = request.getServletPath();
// do somehting here
System.out.println(mapping); // Will print /ui/report/win
return "win_report"
}
Background:
I am developing an web application with Spring MVC.
I want to make an aspect that is executed on POST requests and not executed on GET requests, because I want to inject the logic that prevent POST requests which are sent before completion of HTML rendering.
#RequestMapping(value = "/aaa", method = RequestMethod.POST)
public String methodForPost(AnDto dto, Model model) {
// the aspect should be executed on this method
}
#RequestMapping(value = "/bbb", method = RequestMethod.GET)
public String methodForGET(AnDto dto, Model model) {
// the aspect shouldn't be executed on this method
}
Question:
How can I specify method with an parameterized annotation and its value with #Pointcut ?
How can I specify method with an parameterized annotation and its value in <aop:pointcut> in Spring applicationContext.xml?
#Around(value="#annotation(RequestMapping)")
public Object display(ProceedingJoinPoint joinPoint, RequestMapping requestMapping ) throws Throwable {
// You have access to requestMapping. From which you can get whether its get or post and decide to proceed or not.
}
More info http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-ataspectj-advice-params-passing
You might have to extend this to intercept only for Requestmapping's in your package. Because this intercepts every RequestMappig you might have in your project including one used by the libraries which you might be using, which is a burden.
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);
}