Spring restful service test case fail HTTP status is 500 - rest

I want to implement test case for spring restful web services which return a json
MY controller test class is :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {WebAppContext.class,JpaTestConfiguration.class
})
#WebAppConfiguration
public class DominProfileRestControllerTest {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
private MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(),
Charset.forName("utf8"));
#Before
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
#Test
public void testGetDomainProfile() throws Exception {
String profileId = domainProfile.getId().toString();
System.out.print("testing restful"+profileId);
mockMvc.perform(get("/service/domainprofile/get/{id}", profileId) )
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$.city", is("Chandigrah")));
/* mockMvc.perform(get("/service/domainprofile/get/{id}",profileId).accept(MediaType.TEXT_PLAIN))
.andExpect(status().isOk())
.andExpect(content().contentType("text/plain;charset=ISO-8859-1"))
.andExpect(content().string("hello Prashant"));
*/
}
My Controller class Is :
#RestController
#RequestMapping("/service/domainprofile")
public class DominProfileRestController {
#Autowired
private JpaDomainProfileRepository jpaDomainProfileRepository;
#RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
public DomainProfileResource getDomainProfile(#PathVariable String id) {
JpaDomainProfile domainProfile = jpaDomainProfileRepository.findOne(Long.valueOf(id));
DomainProfileResource domainProfileResource = new DomainProfileResource();
System.out.println("domainProfile.getCity()*************" + domainProfile.getCity());
System.out.println("domainProfile.getAddress()*************" + domainProfile.getAddress());
domainProfileResource.setCity(domainProfile.getCity());
domainProfileResource.setAddress(domainProfile.getAddress());
// return new ResponseEntity<DomainProfileResource>(domainProfileResource, HttpStatus.OK);
return domainProfileResource;
// return domainProfile;
}
}
When I run test case I got An error while we got values in domainprofile.city and domainprofile.address.
Error Is :
java.lang.AssertionError: Status
Expected :200
Actual :500
It Is Working Fine When I return a plain text

can you do this
mockMvc.perform(get("/service/domainprofile/get/{id}", profileId) )
.andDo(print());
this will print the full response with exception , now if you see HttpMessageNotWritableException which was the issue I was facing , you should try to serialize your object using jackson and see if it works (spring internally uses Jackson ). For example , If any of your fields are null the Serialization will fail.

Related

JUnit5 - Rest API controller having custom spring validator is failing

I have a controller that accepts path parameter called 'jobName'. The #ValidateJobName is the custom validator that validates the user input. If the input is wrong then it throws the error below
"Invalid Job name, valid job names are: vendor, service, product,
pricing, currency, contract"
The issue I am facing is that, when I am testing my rest controller API the test case always fails by returning the above error even when the job name is one of the acceptable values but when I remove #ValidateJobName custom annotation from the controller my test cases gets passed.
The #ValidateJobName and Controller works all good when triggered from Postman client but when I do unit testing the test case fails.
I have tried lot of blogs and googled but could not get a solution, Below are my Controller and JUnit testcase.
Please help!
JobController.java
#Validated
#Slf4j
#RestController
public class JobController {
#Autowired
ReportService reportService;
#Autowired
ReportConfig reportConfig;
#RequestMapping(value = "/importjob/{jobName}", method = RequestMethod.GET)
ResponseEntity<DataIntegrationResponse> getReport(#PathVariable #ValidateJobName String jobName) throws Exception {
log.info("Received a request to launch the " + jobName + " Job");
return reportService.getReport(jobName);
}
}
JobControllerTest.java
#ExtendWith(MockitoExtension.class)
#WebMvcTest(JobController.class)
#AutoConfigureMockMvc
public class JobControllerTest {
#MockBean
ReportService reportService;
#MockBean
ReportConfig rep;
#MockBean
JobMapping jmap;
#Autowired
public MockMvc mockMvc;
#Test
public void testGetReport() throws Exception {
String jobNameInput="vendor";
HttpStatus httpStatus = HttpStatus.OK;
String fitsReportName = "idex_fits_vendor.csv";
String jobName = "WFitsVendorJob";
String jobStatus = "STARTED";
Long jobInstanceId = 1022L;
String message = "WFitsVendorJob triggered successfully.";
DataIntegrationResponse response = new DataIntegrationResponse(LocalDateTime.now(), httpStatus, fitsReportName, jobName, jobStatus, jobInstanceId, message);
ResponseEntity<DataIntegrationResponse> responseEntity = new ResponseEntity<DataIntegrationResponse>(response, HttpStatus.OK);
Mockito.when(reportService.getReport(jobNameInput)).thenReturn(responseEntity);
mockMvc.perform(get("/importjob/{jobName}", "vendor")).andExpect(status().isOk());
}
JobNameValidator.java
#Component
public class JobNameValidator implements ConstraintValidator<ValidateJobName, String>{
#Autowired
private JobMapping jobMap;
#Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value!=null && !jobMap.getMappings().containsKey(value)) { return false; }
return true;
}
}
ValidateJobName.java - interface
#Documented
#Constraint(validatedBy = JobNameValidator.class)
#Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
#Retention(RUNTIME)
public #interface ValidateJobName {
String message() default "Invalid Job name, valid job names are: vendor, service, product, pricing, currency, contract";
Class<?>[] groups() default {};
Class<? extends Payload> [] payload() default {};
}
This is because you use a mock of JobMapping
#MockBean
JobMapping jmap;
Your JobNameValidator receive a Mock and doesn't know what to return when calling the containsKey method.
First solution is to tell what to do with this mock :
Mockito.when(jobMapping.getMappings()).thenReturn(// Map containing "vendor");
The second solution is to import your real JobMapping class instead of a mock:
#ExtendWith(MockitoExtension.class)
#WebMvcTest(JobController.class)
#AutoConfigureMockMvc
#Import(JobMapping.class)
class JobControllerTest {
// #MockBean
// JobMapping jmap;
}

Spring Contract does not reach method #Before on base class

I have a single spring contract test:
public class ContractVerifierTest extends BaseClassForIntegrationTests {
#Test
public void validate_shouldSayHello() throws Exception {
// given:
RequestSpecification request = given()
.header("Content-Type", "application/json");
// when:
Response response = given().spec(request)
.get("/sayhello/Eduardo");
// then:
assertThat(response.statusCode()).isEqualTo(200);
assertThat(response.header("Content-Type")).matches("application/json.*");
// and:
DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
assertThatJson(parsedJson).field("['msg']").isEqualTo("hello Eduardo");
}
}
My base class looks like:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = DemoApplication.class, webEnvironment = WebEnvironment.DEFINED_PORT)
#Slf4j
public class BaseClassForIntegrationTests {
#Value("${app.url}") private String url;
#Value("${app.port}") private int port;
#Before
public void setup() {
log.error("Running setup with url:" + url + ":" + port);
RestAssured.baseURI = url;
RestAssured.port = port;
}
}
The setup method is never reached, funny thing, if I change the annotation to #BeforeEach or #BeforeAll it works as expected.
I have a sample of the project here
With Contract 3.0.x the default testing framework is junit5 you need to Configure the plugin explicitly to use junit 4

spring-boot test: #get request returns with body null

while doing Content-negotiation testing mock GET returns with null in response body although response status is 200.
java.lang.AssertionError: Response header 'Content-Type'
Expected :application/json;charset=UTF-8
Actual :null
here is full test class code. I want to verify that content type is json.
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
#AutoConfigureMockMvc
public class ControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
Controller controller;
#Test
public void test() throws Exception {
mockMvc.perform(get("/query?mediaType=json"))
.andExpect(status().isOk())
.andExpect(header().string(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE));
}}
here is my controller's endpoint.
#RestController
public class Controller {
#RequestMapping(value = "/query", produces = {"application/json", "application/xml"}, method = RequestMethod.GET)
public #ResponseBody ResultSet getResults(
final HttpServletRequest request
) throws Throwable {
// logic ...
SearchService search = (SearchService) context.getBean("search");
ResultSet result = search.getResults();
return result;
}
Any thoughts why Body would return as null?
The issue is with your Controller definition in your Test class. As you are testing your Controller, you should be using an actual instance of it. Get you mockMvc instance for this Controller as below (you can do it in your #Before annotated setup method):
mockMvc = MockMvcBuilders.standaloneSetup(new Controller()).build();

How to get oAuth2 access token when user call signup rest API in springboot?

currently I am working on Springboot security, its quite new for me. I followed youtube video tutorial Video
I am getting oauth2 access_token successfully when I use bellow code snippet:-
#SpringBootApplication
public class MathifyApplication {
#Autowired
private PasswordEncoder passwordEncoder;
public static void main(String[] args) {
SpringApplication.run(MathifyApplication.class, args);
}
#Autowired
public void authenticationManager(AuthenticationManagerBuilder builder, UserRepository repository, UserService service) throws Exception {
//Setup a default user if db is empty
User students = new User("stu1", "user", "user", "abc#gmail.com", "1234567890", "12th", "dwarka sec-12",
0, 0 , "may/29/2017", "", Arrays.asList(new Role("USER"), new Role("ACTUATOR")));
if (repository.count()==0){
service.save(students);
}
builder.userDetailsService(userDetailsService(repository)).passwordEncoder(passwordEncoder);
}
private UserDetailsService userDetailsService(final UserRepository repository) {
return userName -> new CustomUserDetails(repository.findByUsername(userName));
}
}
And Controller Class is:-
#RestController
public class LoginController {
#Autowired
private UserService userService;
#RequestMapping(value = "/mathify/getuser/{userId}", method = RequestMethod.GET)
public User getUser(#PathVariable String userId){
System.out.println("Userid "+userId);
return userService.getUser(userId);
}
#RequestMapping(method = RequestMethod.POST, value="/mathify/signup")
public User register(#RequestBody User user){
return userService.doSignup(user);
}
#GetMapping(value="/hi")
public String test(){
return "Oh ! I am fine without secuirity";
}
}
With above code snippet I can get access_token(/oauth/token), and I can also call other controller class private APIs without any issue.
but there is a problem with above code. What? In above code snippet User is hard coded, but when I want to get access_token at the time of user signup it's giving an exception.
2017-06-18 11:04:05.689 ERROR 8492 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: Cannot apply org.springframework.security.config.annotation.authentication.configurers.userdetails.DaoAuthenticationConfigurer#6b66d7ac to already built object] with root cause
java.lang.IllegalStateException: Cannot apply org.springframework.security.config.annotation.authentication.configurers.userdetails.DaoAuthenticationConfigurer#6b66d7ac to already built object
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.add(AbstractConfiguredSecurityBuilder.java:196) ~[spring-security-config-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.apply(AbstractConfiguredSecurityBuilder.java:133) ~[spring-security-config-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder.apply(AuthenticationManagerBuilder.java:290) ~[spring-security-config-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder.userDetailsService(AuthenticationManagerBuilder.java:187) ~[spring-security-config-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at com.techiesandeep.mathify.controller.LoginController.register(LoginController.java:40) ~[classes/:na]
for achieving above described feature I did some changes in my Application and Controller
Application Class is As:-
#SpringBootApplication
public class MathifyApplication {
#Autowired
private PasswordEncoder passwordEncoder;
public static void main(String[] args) {
SpringApplication.run(MathifyApplication.class, args);
}
}
and Controller class is as:-
#RestController
public class LoginController {
#Autowired
private UserService userService;
#Autowired
AuthenticationManagerBuilder builder;
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
private UserRepository repository;
#RequestMapping(value = "/mathify/getuser/{userId}", method = RequestMethod.GET)
public User getUser(#PathVariable String userId){
System.out.println("Userid "+userId);
return userService.getUser(userId);
}
#RequestMapping(method = RequestMethod.POST, value="/user/signup")
public User register(#RequestBody User user) throws Exception {
User u = userService.doSignup(user);
builder.userDetailsService(userDetailsService(repository)).passwordEncoder(passwordEncoder);
return u;
}
private UserDetailsService userDetailsService(final UserRepository repository) {
return userName -> new CustomUserDetails(repository.findByUsername(userName));
}
#GetMapping(value="/hi")
public String test(){
return "Oh ! I am fine without secuirity";
}
}
Any help would be appreciable.thanks
You can call another POST request to get access token.
I am not sure it's the best way, but worked fine with me.
Example code snip inside Signup Request mapping:
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", auth_header);
/*auth_header should be Autorization header value that captured from signup request, which is generated by Basic Auth with clientID and secret, for example, "Basic bXktdHJ1c3RlZC1jbGllbnQ6c2VjcmV0" */
HttpEntity<String> entity = new HttpEntity<String>("",headers);
String authURL = "http://localhost:8080/oauth/token?grant_type=password&username=yourusername&password=yourpassword";
ResponseEntity<String> response = restTemplate.postForEntity(authURL, entity, String.class);
System.out.println(response.getBody());

How to extract path variable from responseentity in Junit testing

Searched but unfortunately I do not get similar questions. I've pasted my involved codes. It uses Spring DATA framework.
Entity EscalationPolicy with ID automatically generated
controller to hand POST request to create an new policy
update JUnit Test
What I'm trying to do in the test is that first create one new EscalationPolicy with the object set by initTest(). Then fetch and update it. However the ID is unknown and I suppose I need to extract it from the return URI. I don't know how to do it after Mockmvc perform and appreciate any help. Thanks!
#Entity
#Table(name = "T_ESCALATIONPOLICY")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class EscalationPolicy implements Serializable {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid")
private String id;
#Column(name = "policy_name")
private String policy_name;
...
}
#RestController
#RequestMapping("/api")
public class EscalationPolicyResource {
...
/**
* POST /escalationPolicys -> Create a new escalationPolicy.
*/
#RequestMapping(value = "/escalationPolicys",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<Void> create(#RequestBody EscalationPolicy escalationPolicy) throws URISyntaxException {
log.debug("REST request to save EscalationPolicy : {}", escalationPolicy);
if (escalationPolicy.getId() != null) {
return ResponseEntity.badRequest().header("Failure", "A new escalationPolicy cannot already have an ID").build();
}
escalationPolicyRepository.saveAndFlush(escalationPolicy);
return ResponseEntity.created(new URI("/api/escalationPolicys/" + escalationPolicy.getId())).build();
}
...
}
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
#IntegrationTest
public class EscalationPolicyResourceTest {
#Before
public void initTest() {
escalationPolicy = new EscalationPolicy();
escalationPolicy.setPolicy_name("Policy Test");
...
}
#Test
#Transactional
public void updatePolicy() throws Exception {
// Create the EscalationPolicy
restEscalationPolicyMockMvc.perform(post("/api/escalationPolicys")
.contentType(TestUtil.APPLICATION_JSON_UTF8)
.content(TestUtil.convertObjectToJsonBytes(escalationPolicy)))
.andExpect(status().isCreated());
// Get the created policy
EscalationPolicy e = escalationPolicyRepository.findOne(id);
~~need ID here
}
...
}
Though it may not be the most elegant way to deal with it, I think a way to bypass the problem. I save the id in the header map and in the test code to extract it.
#RestController
#RequestMapping("/api")
public class EscalationPolicyResource {
...
/**
* POST /escalationPolicys -> Create a new escalationPolicy.
*/
#RequestMapping(value = "/escalationPolicys",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<Void> create(#RequestBody EscalationPolicy escalationPolicy) throws URISyntaxException {
log.debug("REST request to save EscalationPolicy : {}", escalationPolicy);
if (escalationPolicy.getId() != null) {
return ResponseEntity.badRequest().header("Failure", "A new escalationPolicy cannot already have an ID").build();
}
escalationPolicyRepository.saveAndFlush(escalationPolicy);
HttpHeaders headers = new HttpHeaders();
headers.set("policyID", escalationPolicy.getId());
return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
}
...
}
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
#IntegrationTest
public class EscalationPolicyResourceTest {
#Before
public void initTest() {
escalationPolicy = new EscalationPolicy();
escalationPolicy.setPolicy_name("Policy Test");
...
}
#Test
#Transactional
public void updatePolicy() throws Exception {
// Create the EscalationPolicy
ResultActions action =
restEscalationPolicyMockMvc.perform(post("/api/escalationPolicys")
.contentType(TestUtil.APPLICATION_JSON_UTF8)
.content(TestUtil.convertObjectToJsonBytes(escalationPolicy)));
action.andExpect(status().isCreated());
id = (String)action.andReturn().getResponse().getHeaderValue("policyID");
// Get the created policy
EscalationPolicy e = escalationPolicyRepository.findOne(id);
}
...
}