Spring Boot Controller Test with Mock Service doesn't use the mock service - junit4

I have a simple RestController with a Service and want to test just the controller by providing a mock implementation for the Service.
However, I'm getting an empty response in resultActions = mockMvc.perform(get("/user")); object when I'm running the test.
Here is my code:
Controller
#RestController
public class UserController {
#Autowired
UserService userService;
#GetMapping("/user")
public ResponseEntity<List<String>> getUsers(){
return ResponseEntity.ok().body(userService.getUsers());
}
}
Contoller Test
#RunWith(SpringRunner.class)
#WebMvcTest(UserController.class)
public class UserControllerTest {
#MockBean
UserService userService;
private final Logger log = LoggerFactory.getLogger(UserControllerTest.class);
#Autowired
MockMvc mockMvc;
#Before
public void init(){
List<String> usrs = new ArrayList<>();
usrs.add("JUNIT-USER");
userService = Mockito.mock(UserService.class);
when(userService.getUsers()).thenReturn(usrs);
}
#Test
public void test1() throws Exception {
ResultActions resultActions = mockMvc.perform(get("/user"));
resultActions.andDo(mvcResult -> {
log.info(mvcResult.getResponse().getContentType());
log.info(mvcResult.getResponse().getContentAsString());
log.info(String.valueOf(mvcResult.getResponse().getContentLength()));
});
resultActions
.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.content().json("[\"JUNIT-USER\"]"));
}
}
The output of the log statements in the test is as follows:
2021-02-24 15:23:16.161 INFO 22197 --- [ main] com.vi.learn.UserControllerTest : application/json
2021-02-24 15:23:16.161 INFO 22197 --- [ main] com.vi.learn.UserControllerTest : []
2021-02-24 15:23:16.161 INFO 22197 --- [ main] com.vi.learn.UserControllerTest : 0
The test hence fails with the below assertionError:
java.lang.AssertionError: []: Expected 2 values but got 0
What am I doing wrong here?

Two existing methods
Using the mock () method
Using the #MockBean annotation
#MockBean
UserService userService;
or
userService = Mockito.mock(UserService.class);
You have to choose one of them so simply use #MockBean :
#Before
public void init(){
List<String> usrs = new ArrayList<>();
usrs.add("JUNIT-USER");
when(userService.getUsers()).thenReturn(usrs);
}

Related

Assertion error for testing Junit with reactive WebTestClient Status Expected :201 Actual :404

#ExtendWith(SpringExtension.class)
#WebFluxTest(controllers = EventsControllerTest.class)
class EventsControllerTest {
#MockBean
UserRepo repo;
#Autowired
private WebTestClient webClient;
#Test
void testAssignUserRoles() {
UserInfo user = new UserInfo();
user.setId(Long.valueOf(1));
user.setFirstname("Test");
user.setLastname("Test2");
user.setActiveuser(true);
user.setEmailid("tet#test.com");
user.setRolename("test");
user.setUserpassword("test");
Mockito.when(repo.save(user)).thenReturn(Mono.just(user));
webClient.post().uri("/assignRoles").contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromObject(user)).exchange().expectStatus().isCreated();
Mockito.verify(repo, times(1)).save(user);
}
Controller
#RestController
public class EventsController {
#Autowired
UserInfoRepository userInfoRepository;
#PostMapping(value = "/saveRole")
public Mono<UserInfo> assignUserRoles(#RequestBody UserInfo userInfo) {
return userInfoRepository.save(userInfo).log();
}
Access URI should match value attribute of #PostMapping: saveRole.

Integration Tests for RESTEasy Endpoint

I want to perform integration tests on my REST endpoint but am running into issues.
Below is my endpoint. NOTE: I cannot change this part of the code.
#Path("/people")
public class PersonResource {
private final PersonService personService;
#Inject
public PersonResource(final PersonService personService) {
this.personService = personService;
}
#GET
#Produces("application/json")
public List<Person> getPersonList() {
return personService.getPersonList();
}
}
From what I've been able to find online, I have the following basic structure for my test.
public class PersonResourceTest {
private Dispatcher dispatcher;
private POJOResourceFactory factory;
#Before
public void setup() {
dispatcher = MockDispatcherFactory.createDispatcher();
factory = new POJOResourceFactory(PersonResource.class);
dispatcher.getRegistry().addResourceFactory(factory);
}
#Test
public void testEndpoint() throws URISyntaxException {
MockHttpRequest request = MockHttpRequest.get("people");
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
System.out.print("\n\n\n\n\n" + response.getStatus() + "\n\n\n\n\n");
System.out.print("\n\n\n\n\n" + response.getContentAsString() + "\n\n\n\n\n");
}
}
However, this results in the following error on the last line of the setup method.
java.lang.RuntimeException: RESTEASY003190: Could not find constructor for class: my.path.PersonResource
I explored the Registry API and thought maybe I should have been using addSingletonResource instead, so I changed the last line of setup to dispatcher.getRegistry().addSingletonResource(personResource); and added the following.
#Inject
private PersonResource personResource;
But that results in a NullPointerException on the last line of setup.
The sparse documentation on the mocking isn't very helpful. Can anyone point out where I'm going wrong? Thanks.
You need to do two things
Add a no arguments constructor to your source class:
public PersonResource() {
this(null)
}
In the test class, initialize the PersonResource class with an instance of PersonService class:
dispatcher.getRegistry().addSingletonResource(new PersonResource(new PersonService()));
If needed, the PersonService class can be mocked:
private Dispatcher dispatcher;
#Mock
private PersonService service;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
dispatcher = MockDispatcherFactory.createDispatcher();
PersonResource resource= new PersonResource(service);
ispatcher.getRegistry().addSingletonResource(resource);
}
Hope it helps!

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

spring webclient unit test with mockito

I'm trying to write a test for my controller (which has an autowired field pageModelService)
here is my test class:
#RunWith(MockitoJUnitRunner.class)
public class PageModelControllerTest {
#Mock
private PageModelService pageModelService;
#InjectMocks
private PageModelController pageModelController;
private WebTestClient client;
#Before
public void setup() {
client = WebTestClient.bindToController(pageModelController).build();
}
}
I can't create the client, it tells me it can't autowire pageModelService
any idea

Spring restful service test case fail HTTP status is 500

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.