Mocking spring controller validator - spring

I want to unit test this Spring controller method:
#Autowired
private MyValidator validator;
public String register(
HttpServletRequest request,
ModelMap model,
Principal principal,
#PathVariable Plain plain,
RedirectAttributes ratts,
#ModelAttribute #Valid PlainMoreObject pmo,
BindingResult result)
{
validator.validate(pmo, result);
I'm using JMock. How do I mock the validator in order to test controller by calling
controller.register(....) ?

There is a helper class in Spring called ReflectionTestUtils (link) you can use to inject mocked beans to fields.
#Mock MyValidator validatorMock;
ReflectionTestUtils.setField(controller, "validator", validatorMock);
controller.register(...);

Related

Spring Boot Bean Validation In HashMap Not Working

I am creating a REST controller which shall take a list of Dtos.
It all works but the validation is not working, therefore it fails during persistence only.
My code:
#Valid #RequestBody HashMap<String, MyDto> myDtoMap
And unfortunately the MyDto does not get validated.
I also tried this way:
#Valid #RequestBody HashMap<String, #Valid MyDto> myDtoMap
Please try :
annotate your controller with :
#RestController
#Validated
Then you can validate you class with :
#RequestBody HashMap<String, #Valid MyDto> myDtoMap

Mockito #Spy calls real method while mocking behaviour is defined

I have a common spring boot application consisting of a controller and a service layer. A database is not involved as I use another rest api to store the data.
Now I want to the my controller and therefor I want to mock my sevice partially. Partially because I have one method in it that takes a dto and converts it to my business model. I know this can also be solved with a constructor of the bussiness model but anyway I came to the following problem:
CODE
Controller
#RestController
public class RegistrationController {
#Autowired
private UserRegistrationService userRegistrationService;
#PostMapping(value = "/user", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<UserId> createUser(#RequestBody #Valid UserDto userDto) {
KeycloakUserRepresentation keycloakUserRepresentation = userRegistrationService.convertUserDtoToKeycloakUserRepresentation(userDto);
UserId userId = userRegistrationService.createNewUser(keycloakUserRepresentation);
return new ResponseEntity<>(userId,HttpStatus.CREATED);
}
TEST
#SpringBootTest
#AutoConfigureMockMvc
#ExtendWith({RestDocumentationExtension.class})
#AutoConfigureRestDocs
class RegistrationControllerRegistrationTest {
private static final UserDto testUsertDto = new UserDto();
#Autowired
private MockMvc mockMvc;
#Autowired
private ObjectMapper objectMapper;
#Spy
private UserRegistrationServiceImpl userRegistrationService;
In my test method I define:
doReturn(testUserId).when(userRegistrationService).createNewUser(any(KeycloakUserRepresentation.class));
PROBLEM:
I expect that while not define a doSomething in my test, the conversion of the userDto to a keycloak representation is done by the original method. This seems to work as when I debug in my Controller the keycloakUserRepresentation has the correct values. The problem is that in the next step the
createNewUser
method is not stubbed/mocked. The original method is executed and so my test fails.
What I want is that when I provide a doSomething method in my testcase, I want the original method to be mocked.
This seems to work as when I debug in my Controller the
keycloakUserRepresentation has the correct values.
It worked because the bean wasn't spied on at all. Although #Spy may help in creating a mocked object, it does not result in a mocked Spring bean in your test application context. Use #SpyBean to have Mockito spy on a bean in the Spring application context.

RESTful URI Resource mutual exclusion based on query param in CXF

In Spring MVC, for RESTful service, if URI and HTTP Method are same for two or more different resources, then they can be made mutually exclusive based on query params by using NOT(!) operator with Query Param such as :
#RequestMapping(method = RequestMethod.POST, value = "/authentication", params = { "password", "!ssn" })
#ResponseBody
public SessionResponse userLogin(#Valid #ModelAttribute final UsernameAuthFormBean usernameAuthFormBean,
final BindingResult bindingResult, final HttpServletRequest request, final HttpServletResponse response) {}
#RequestMapping(method = RequestMethod.POST, value = "/authentication", params = { "!password", "ssn" })
#ResponseBody
public SessionResponse forgotPassword(#Valid #ModelAttribute final ForgotPasswordFormBean forgotPasswordFormBean,
final BindingResult bindingResult, final HttpServletRequest request, final HttpServletResponse response) {}
How can this be achieved in CXF?
CXF and Spring MVC are not directly comparable. CXF is an implementation of Java Api for RESTful services JAX-RS
This operator ! is not present in the specification and CXF does not implement it. You need to use different URIs
#POST
#Path("/authentication/userLogin")
public Response userLogin(#FormParam("") UsernameBean bean)
#POST
#Path("/authentication/forgotPassword")
public Response forgotPassword(#FormParam("") ForgotPasswordBean bean)

#Autowired for #ModelAttribute

I'm very new to Spring and I'm encountering the following problem.
I've got the following Controller, in which the #Autowired works perfectly (tried debugging and it works fine).
#Controller
#RequestMapping(value = "/registration")
#SessionAttributes("rf")
public class RegistrationController
{
#Autowired
UserJpaDao userDao;
#RequestMapping(method = RequestMethod.GET)
#Transactional
public String setupForm(Model model) throws Exception
{
model.addAttribute("rf", new RegistrationForm());
return "registration";
}
#RequestMapping(method = RequestMethod.POST)
#Transactional
public String submitForm(#ModelAttribute("rf") RegistrationForm rf, Model model) throws Exception
{
// ...
User user = rf.getUser();
userDao.save(user);
// ...
return "registration";
}
}
But when I submit my form, the #Autowired field in my RegistrationForm remains null.
RegistrationForm.java:
#Component
public class RegistrationForm
{
#Autowired
CountryJpaDao countryDao;
// ... fields...
public RegistrationForm()
{
}
#Transactional
public User getUser() throws InvalidUserDataException
{
//...
Country c = countryDao.findByCode("GB"); // Throws java.lang.NullPointerException
// ...
}
// ... getters/setters...
}
Here is the form's HTML/JSTL:
<form:form method="POST" modelAttribute="rf">
...
</form:form>
Can anyone help me?
Thank you.
(inspired by this post on SpringSource forums)
You're mixing up your concepts here. You use the likes of #Component and #Autowired for Spring-managed beans, and #ModelAttribute for transient, throwaway objects that are used to bind form data. The two should not be mixed. Your #Component and #Autowired annotations on RegistrationForm will be ignored by Spring, because they're not appropriate in that context.
Classes like RegistrationForm should represent the form data, and nothing else. Typically, the controller would ask RegistrationForm for the user ID, and would then look at the actual User object from the DAO itself. If you want RegistrationForm to look up the User itself, then your controller needs to manually supply the DAO to RegistrationForm when it asks for the User object.
As far as that post on the Spring forum is concerned, you'll notice that it never received an answer. It's not a good source to take inspiration from.
Note that I'm not saying that desiring to autowire beans into a form back object is a bad idea, I'm just saying that Spring doesn't do that.
It would work if you use the #Configurable annotation on your model, and this aspectJ configuration on your gradle file:
compileJava << {
ant.taskdef(
resource: 'org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties',
classpath: configurations.compile.asPath)
ant.iajc(
inpath: sourceSets.main.output.classesDir.absolutePath,
classpath: configurations.compile.asPath,
aspectPath: configurations.aspects.asPath,
destDir: sourceSets.main.output.classesDir.absolutePath
)
}
In this way aspectJ will generate code that does the auto wiring.
#Configurable
public class RegistrationForm
{
...
}

Spring 3 MVC Controller integration test - inject Principal into method

As part of Spring 3 MVC it is possible to inject the currently logged in user (Principle) object into a controller method.
E.g.
#Controller
public class MyController {
#RequestMapping(value="/update", method = RequestMethod.POST)
public String update(ModelMap model, Principal principal) {
String name = principal.getName();
... the rest here
}
}
This is documented as part of the Spring 3 documentation here:
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping-arguments.
This works in the production code. However I don't know how to test this.
When I create an integration test (having set up spring security context as well)
and call the controller handle method then the Principal is always null!
public class FareTypeControllerIntegrationTest extends SpringTestBase {
#Autowired
private MyController controller;
#Autowired
private AnnotationMethodHandlerAdapter handlerAdapter;
private final MockHttpServletRequest request = new MockHttpServletRequest();
private final MockHttpServletResponse response = new MockHttpServletResponse();
#Test
public void testUpdate() throws Exception {
request.setRequestURI("/update");
request.setMethod(HttpMethod.POST.name());
... setup rest of request
ModelAndView mav = handlerAdapter.handle(request, response, controller);
.. rest of assertions
}
The tests are running correctly and everything except the Principal is null.
Any ideas?
TIA
Ayub
After a quick look into Spring sources this should work:
request.setUserPrincipal(somePrincipal);
I've tried to do this some time ago, here is the method i used to set up authentication.
protected void setSecurityContext(String login){
userDetailsTest = userManager.loadUserByUsername(login);
TestingAuthenticationToken testingAuthenticationToken = new TestingAuthenticationToken(userDetailsTest, userDetailsTest.getAuthorities());
SecurityContext securityContext = new SecurityContextImpl();
securityContext.setAuthentication((Authentication) testingAuthenticationToken);
SecurityContextHolder.setContext(securityContext);
}
Then i just call it in the #Before method of the test.
Hope it helps.
I do something like this in my tests prior to calling code using Spring Security (such as the Principal parameter resolver you are testing):
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("wiseau", "Love is blind"));

Resources