How to test #ModelAttrbiute in spring boot controller test? - java

i have a problem testing an endpoint which use #ModelAttribute I don't know very well how to test with this annotation and the test response is java.lang.AssertionError: Content type not set , here is the controller method:
#PostMapping
public ResponseEntity<?> createTestimonials(#ModelAttribute(name = "testimonialsCreationDto") #Valid TestimonialsCreationDto testimonialsCreationDto) {
try {
return ResponseEntity.status(HttpStatus.CREATED).body(iTestimonials.createTestimonials(testimonialsCreationDto));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.CONFLICT).body(e.getMessage());
}
}
Here is the test:
#Test
void createTestimonials() throws Exception {
//Given
String name = "Testimonio 159";
String contentTestimonial = name + " content!";
TestimonialsCreationDto testimonialsCreationDto = new TestimonialsCreationDto();
testimonialsCreationDto.setName(name);
testimonialsCreationDto.setContent(contentTestimonial);
//When
mockMvc.perform(post("/testimonials")
.flashAttr("testimonialsCreationDto", testimonialsCreationDto)
.contentType(MediaType.MULTIPART_FORM_DATA)
.content(objectMapper.writeValueAsString(testimonialsCreationDto))
.characterEncoding("UTF-8"))
//Then
.andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.name", is(name)))
.andExpect(jsonPath("$.content", is(contentTestimonial)));
verify(testimonialsService).createTestimonials(any());
}
MockHttpServletRequest:
HTTP Method = POST
Request URI = /testimonials
Parameters = {}
Headers = [Content-Type:"multipart/form-data;charset=UTF-8", Content-Length:"74"]
Body = {"name":"Testimonio 159","image":null,"content":"Testimonio 159 content!"}
Session Attrs = {}
MockHttpServletResponse:
Status = 200 ---> IDK why response with 200 code
Error message = null
Headers = []
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
java.lang.AssertionError: Content type not set

You have to add path value to PostMapping :
#PostMapping(path = "/testimonials", produces = MediaType.MULTIPART_FORM_DATA)

Related

How to pass a json object into a test controller in springboot?

I am trying to create a controller test in springboot that tests whether the controller method adds a new line into my database (I have configured a h2 in memory database). I keep getting errors. I want to pass the data into the controller in json form like this:
{"type":"epidemics",
"questionIndex":21,
"choiceNum":4,
"question":"second question",
"choiceA": "no1",
"choiceB":"yes2",
"choiceC":"no3",
"choiceD":"yes4",
"correct":"no1",
"hint":"second answer"
}
but I keep getting errors. My code is below:
controller
#PostMapping("/adminadd")
public QuizDTO addQuestion(#RequestBody QuizDTO quizDTO) {
return quizRepo.addQuestion(quizDTO);
}
jdbc repo
private static final String INSERT_QUESTION = "INSERT INTO Quiz(type,questionIndex,choiceNum,question,choiceA,choiceB,choiceC,choiceD,correct,hint) values(?,?,?,?,?,?,?,?,?,?)";
#Override
public QuizDTO addQuestion(QuizDTO quizDTO) {
jdbcTemplate.update(INSERT_QUESTION, quizDTO.getType(), quizDTO.getquestionIndex(), quizDTO.getChoiceNum(), quizDTO.getQuestion(), quizDTO.getChoiceA(),
quizDTO.getChoiceB(), quizDTO.getChoiceC(), quizDTO.getChoiceD(), quizDTO.getCorrect(), quizDTO.getHint());
return quizDTO;
}
Test
#RunWith(SpringRunner.class)
#WebMvcTest(QuizController.class)
//#AutoConfigureMockMvc
public class QuizControllerTest {
#MockBean
private QuizRepository quizRepository;
#Autowired
private MockMvc mockMvc;
#Test
void shouldAddQuestion() throws Exception {
QuizDTO quizDTO = new QuizDTO(104, "epidemics", 21, 4, "Test Question?", "A", "B", "C", "D", "hint");
mockMvc.perform(post("/adminadd").contentType(MediaType.APPLICATION_JSON_VALUE)
.param("ID", "104")
.param("Type", "Epidemics")
.param("questionIndex", "21")
.param("choiceNum", "4")
.param("question", "Test Q")
.param("choiceA", "A")
.param("choiceB", "B")
.param("choiceC", "C")
.param("choiceD", "D")
.param("correct", "B")
.param("Hint", "hint"))
.andExpect(status().isOk())
.andExpect(content().string(containsString("Test Q")));;
}
}
error:
MockHttpServletRequest:
HTTP Method = POST
Request URI = /adminadd
Parameters = {ID=[104], Type=[Epidemics], questionIndex=[21], choiceNum=[4], question=[Test Q], choiceA=[A], choiceB=[B], choiceC=[C], choiceD=[D], correct=[B], Hint=[hint]}
Headers = [Content-Type:"application/json;charset=UTF-8"]
Body = null
Session Attrs = {org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN=org.springframework.security.web.csrf.DefaultCsrfToken#22899683}
Handler:
Type = null
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 403
Error message = Forbidden
Headers = [X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
Status expected:<200> but was:<403>

Why the controller method returns void content of response in the test method?

I'm learning Java Spring and trying to write a test of a controller method. That is, I want to perform a controller method by its path and check if the returning content contains some sequence of symbols. For example, my test is invoking a content on the page by address "user/1" and expecting that content will contain "root".
Unfortunately, performing "user/1" returns null content, although it's possible to input this route in a browser and get a page of this user without any problems.
Here is my controller method that I want to test
#GetMapping("/{id}")
public String view(#PathVariable(value = "id") Integer id, Model model) throws EntityNotFoundException {
try {
User item = users.get(id);
model.addAttribute("item", item);
model.addAttribute("posts", posts.getLatestByUser(item, 10));
model.addAttribute("comments", comments.getLatestByUser(item, 10));
return "user/view";
} catch (IllegalArgumentException ex) {
throw new EntityNotFoundException("Cannot find a user with id = " + id);
}
}
here is my class for testing
#SpringBootTest(classes = {
Main.class,
TestDataConfig.class,
TestWebConfig.class
})
#ActiveProfiles("test")
#AutoConfigureMockMvc
#Sql(value = {"/create-tables.sql", "/fill-tables.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
public class UserCtrlTest {
#Autowired
private UserCtrl controller;
#Autowired
private MockMvc mockMvc;
#Test
#WithAnonymousUser
public void shouldDisplayUserInfoUponWatchingUserPage() throws Exception {
MvcResult result = this.mockMvc.perform(get("/user/1"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(view().name("user/view"))
.andReturn();
String stringResult = result.getResponse().getContentAsString();
Assert.assertTrue(stringResult.contains("<h4>root</h4>"));
}
}
Here is my view resolver class
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver bean = new InternalResourceViewResolver();
bean.setViewClass(JstlView.class);
bean.setPrefix("/WEB-INF/views/");
bean.setSuffix(".jsp");
return bean;
}
Here is result that the method .andDo(print()) returns in the console
MockHttpServletRequest:
HTTP Method = GET
Request URI = /user/1
Parameters = {}
Headers = []
Body = null
Session Attrs = {}
Handler:
Type = ru.job4j.forum.controller.UserCtrl
Method = ru.job4j.forum.controller.UserCtrl#view(Integer, Model)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = user/view
View = null
Attribute = item
value = ru.job4j.forum.model.User#20
errors = []
Attribute = posts
value = [ru.job4j.forum.model.Post#20, ru.job4j.forum.model.Post#21]
Attribute = comments
value = [ru.job4j.forum.model.Comment#21, ru.job4j.forum.model.Comment#24]
Attribute = user
value = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [Content-Language:"en", X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
Content type = null
Body =
Forwarded URL = /WEB-INF/views/user/view.jsp
Redirected URL = null
Cookies = []
MockHttpServletRequest:
HTTP Method = GET
Request URI = /user/1
Parameters = {}
Headers = []
Body = null
Session Attrs = {}
Handler:
Type = ru.job4j.forum.controller.UserCtrl
Method = ru.job4j.forum.controller.UserCtrl#view(Integer, Model)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = user/view
View = null
Attribute = item
value = ru.job4j.forum.model.User#20
errors = []
Attribute = posts
value = [ru.job4j.forum.model.Post#20, ru.job4j.forum.model.Post#21]
Attribute = comments
value = [ru.job4j.forum.model.Comment#21, ru.job4j.forum.model.Comment#24]
Attribute = user
value = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [Content-Language:"en", X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
Content type = null
Body =
Forwarded URL = /WEB-INF/views/user/view.jsp
Redirected URL = null
Cookies = []
Could you help me to understand why the request doesn't return the content of the page? And how to solve this problem? If you need other sources and screenshots to clarify the situation, please, write about that and I will add them.

How to add a file and body to MockMvc?

Using Spring boot 2 and Spring mvc. I am trying to test my rest controller using mockMvc
#PostMapping(
value = "/attachment")
public ResponseEntity attachment(MultipartHttpServletRequest file, #RequestBody DocumentRequest body) {
Document document;
try {
document = documentService.process(file.getFile("file"), body);
} catch (IOException | NullPointerException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
return ResponseEntity.accepted().body(DocumentUploadSuccess.of(
document.getId(),
"Document Uploaded",
LocalDateTime.now()
));
}
I could attach the file successfully on my test but know I added a body and I can't receive both attached
#Test
#DisplayName("Upload Document")
public void testController() throws Exception {
byte[] attachedfile = IOUtils.resourceToByteArray("/request/document-text.txt");
MockMultipartFile mockMultipartFile = new MockMultipartFile("file", "",
"text/plain", attachedfile);
DocumentRequest documentRequest = new DocumentRequest();
documentRequest.setApplicationId("_APP_ID");
MockHttpServletRequestBuilder builder =
MockMvcRequestBuilders
.fileUpload("/attachment")
.file(mockMultipartFile)
.content(objectMapper.writeValueAsString(documentRequest));
MvcResult result = mockMvc.perform(builder).andExpect(MockMvcResultMatchers.status().isAccepted())
.andDo(MockMvcResultHandlers.print()).andReturn();
JsonNode response = objectMapper.readTree(result.getResponse().getContentAsString());
String id = response.get("id").asText();
Assert.assertTrue(documentRepository.findById(id).isPresent());
}
I got 415 status error
java.lang.AssertionError: Status expected:<202> but was:<415>
Expected :202
Actual :415
How could I fix it?
You're getting status 415: unsupported media type.
You needed to changed add contentType() of the request which the controller accepts.
If your controller accepts application/json:
MockHttpServletRequestBuilder builder =
MockMvcRequestBuilders
.multipart("/attachment")
.file(mockMultipartFile)
.content(objectMapper.writeValueAsString(documentRequest))
.contentType(MediaType.APPLICATION_JSON);// <<<

Springboot Junit Test expect 200 but getting 403 forbidden

I am Junit testing a controller which uses a JPA repositroy for the database. My H2 in memory database is working correctly, and my GET Request mapping is working as expected. My PUT is getting a 403, while I expect a 200. I've tried a variety of different configurations using AutoConfigureMockMvc with secure false, and also excluding security auto configuration.
Is there something I am missing regarding PUT requests, the security configuration, or need to add configuration around the tokens?
Here is my Junit Test, saveTest works correctly while updateTest returns a 403.
#EnableAutoConfiguration(exclude = SecurityAutoConfiguration.class)
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc(secure = false)
#Import(SecurityConfig.class)
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class DBcontroltest {
#Autowired
DbRequest dbRequest;
#Autowired
ConnectionRequestRepository connectionRequestRepository;
#Autowired
private MockMvc mockMvc;
private String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
private SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
private Date date;
private String dateFormatted = "2019-11-26T14:33:13.175+0000";
{
try {
date = simpleDateFormat.parse("2019-11-26T14:33:13.175+0000");
} catch (ParseException e) {
e.printStackTrace();
}
}
#Test
public void saveTest() throws Exception {
ConnectionRequest connectionRequest = new ConnectionRequest((long) 1, "bleep", "market", "dev", "conn1", "fun", "java", "styff", "hello", "whoop", date, "dldl");
connectionRequestRepository.save(connectionRequest);
String body = "{\"connectionId\":1,\"requestor\":\"bleep\",\"market\":\"market\",\"platform\":\"dev\",\"environment\":\"conn1\",\"connectionName\":\"fun\",\"connectionType\":\"java\",\"databaseId\":\"styff\",\"databasePwd\":\"hello\",\"email\":\"whoop\",\"requestDate\":\"" + dateFormatted + "\",\"jobStatus\":\"dldl\"}\n" +
" ";
mockMvc.perform(get("/api/selectDB/{connectionId}" ,1))
.andExpect(content().json(body))
.andExpect(status().isOk());
}
#Test
public void updateTest() throws Exception {
ConnectionRequest connectionRequest = new ConnectionRequest((long) 1, "bleep", "market", "dev", "conn1", "connname", "java", "db", "hello", "email#aol.com", date, "done");
connectionRequestRepository.save(connectionRequest);
String body3 = "{\"requestor\":\"NEWGUY\"}";
MockHttpServletRequestBuilder builder =
MockMvcRequestBuilders.put("/api/updateDB/{connectionId}" ,1)
.contentType("application/json")
.content(body3);
System.out.println(connectionRequestRepository.findById((long) 1));
this.mockMvc.perform(builder)
.andExpect(MockMvcResultMatchers.status()
.isOk())
.andDo(MockMvcResultHandlers.print());
System.out.println(connectionRequestRepository.findById((long) 1));
}
}
Here is my controller,
#Data
#RestController
#RequestMapping("/api/")
public class DbRequest {
#Autowired
private ConnectionRequestRepository connectionRequestRepository;
private ConnectionRequest connectionRequest;
#GetMapping("/selectDB/{connectionId}")
public ResponseEntity<ConnectionRequest> getRequestById(#PathVariable("connectionId") Long connectionId) throws Exception {
ConnectionRequest connectionRequest = connectionRequestRepository.findById(connectionId)
.orElseThrow(() -> new Exception("Connection Request " + connectionId + " not found"));
return ResponseEntity.ok().body(connectionRequest);
}
#PutMapping("/updateDB/{connectionId}")
public ResponseEntity<ConnectionRequest> updateConnectionRequest(#PathVariable("connectionId") Long connectionId,
#Valid #RequestBody ConnectionRequest connectionRequestDetails) throws Exception {
long completedDateTime = System.currentTimeMillis();
System.out.println("completeDateTime is " + completedDateTime);
ConnectionRequest connectionRequest = connectionRequestRepository.findById(connectionId)
.orElseThrow(() -> new Exception("Connection Request " + connectionId + " not found"));
System.out.println("value for connectionrequest is " + connectionRequest);
System.out.println("value for connectionrequestdetails is " + connectionRequestDetails);
connectionRequest.setRequestor(connectionRequestDetails.getRequestor());
final ConnectionRequest updatedConnectionRequest = connectionRequestRepository.save(connectionRequest);
return ResponseEntity.ok(updatedConnectionRequest);
}
}
This is the output from running the junit test, with good data. I've tested the application, and it's working as expected, only Junit fails.
MockHttpServletRequest:
HTTP Method = PUT
Request URI = /api/updateDB/1
Parameters = {}
Headers = [Content-Type:"application/json;charset=UTF-8"]
Body = {"requestor":"NEWGUY"}
Session Attrs = {org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN=org.springframework.security.web.csrf.DefaultCsrfToken#80b6098}
Handler:
Type = null
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 403
Error message = Forbidden
Headers = [X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
java.lang.AssertionError: Status
Expected :200
Actual :403
<Click to see difference>
By using csrf I was able to get this working correctly.
MockHttpServletRequestBuilder builder =
put("/api/updateDB/{connectionId}", 1)
.contentType("application/json")
.content(body3)
.contentType(MediaType.APPLICATION_JSON)
.with(csrf());
System.out.println(connectionRequestRepository.findById((long) 1));
this.mockMvc.perform(builder)
.andExpect(content().json(body))
.andExpect(status().isOk())
.andDo(MockMvcResultHandlers.print());
System.out.println(connectionRequestRepository.findById((long) 1));
Create the below for test profile.
#EnableWebSecurity
#Configuration
#EnableGlobalMethodSecurity(jsr250Enabled = true)
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("root").password("system").roles("SYSTEM");
}
}
Inside your test class,
public class DBcontroltest {
...
#Test
#WithUserDetails(value = "root")
public void updateTest() throws Exception {
...
}
Please visit this project on github, I have setup spring boot testing using spring-security using spring boot.
Test case: https://github.com/reflexdemon/shop/blob/master/src/test/java/org/shop/service/CatalogServiceTest.java
Config: https://github.com/reflexdemon/shop/blob/master/src/main/java/org/shop/WebSecurityConfig.java

Can't test HTTP status on MockMvc async REST service in spring-test 5.0.3 (works in 5.0.0)

I've generated fresh project using Spring Initializer (https://start.spring.io/)
Spring boot - 2.0.0.RC1 which ships spring in version 5.0.3.RELEASE.
Added the following controller:
#RestController
#ResponseBody
#RequestMapping(value = "/customer")
public class CustomerController {
#GetMapping("/")
public Future<ResponseEntity<String>> get1() {
return CompletableFuture.supplyAsync(() -> new ResponseEntity<String ("not found", HttpStatus.NOT_FOUND));
}
}
and having the following dependencies section in build.gradle (problem can be also replicated on maven build)
dependencies {
compile('org.springframework.boot:spring-boot-starter')
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework:spring-web')
testCompile('org.springframework:spring-test')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
The following test fails:
#SpringBootTest
#RunWith(SpringRunner.class)
#AutoConfigureMockMvc
public class CustomerControllerTest {
#Autowired
private MockMvc mockMvc;
#Test
public void test404() throws Exception {
MvcResult asyncResult = mockMvc.perform(MockMvcRequestBuilders.get("/customer/"))
.andExpect(request().asyncStarted())
.andReturn();
mockMvc.perform(asyncDispatch(asyncResult))
.andExpect(status().isNotFound());
}
}
with the following log:
MockHttpServletRequest:
HTTP Method = GET
Request URI = /customer/
Parameters = {}
Headers = {}
Body = null
Session Attrs = {}
Handler:
Type = com.example.wkicior.demo.CustomerController
Method = public java.util.concurrent.Future<org.springframework.http.ResponseEntity<java.lang.String>> com.example.wkicior.demo.CustomerController.get1()
Async:
Async started = true
Async result = <404 Not Found,not found,{}>
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = {}
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
MockHttpServletRequest:
HTTP Method = GET
Request URI = /customer/
Parameters = {}
Headers = {}
Body = null
Session Attrs = {}
Handler:
Type = com.example.wkicior.demo.CustomerController
Method = public java.util.concurrent.Future<org.springframework.http.ResponseEntity<java.lang.String>> com.example.wkicior.demo.CustomerController.get1()
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = {Content-Type=[text/plain;charset=UTF-8], Content-Length=[9]}
Content type = text/plain;charset=UTF-8
Body = not found
Forwarded URL = null
Redirected URL = null
Cookies = []
java.lang.AssertionError: Status
Expected :404
Actual :200
It seems that the test sees status code as 200, not 404. The body content is returned properly, though.
What's interesting that downgrading to 5.0.0.RELEASE of spring-test - fixes the problem:
testCompile('org.springframework:spring-test:5.0.0.RELEASE')
Is this a spring-test bug?
It seems like spring bug indeed: https://jira.spring.io/browse/SPR-16430
moving to 5.0.4.BUILD-SNAPSHOT resolves the problem

Categories

Resources