Using Spring Boot 1.3.6.RELEASE, i am trying to unit test a controller method using Junit, Mockito and MockMvc. I have built a custom constraint validator (extending ConstraintValidator) which autowires a service. My target entity is annotated with the custom validator annotation and a group. My controller method signature is the following :
@RequestMapping ( value = "api/task/newtask", method = RequestMethod.POST )
public ResponseEntity submitTask ( @Validated ( value = TaskDependenciesDbValidation.class )
@RequestBody Task task )
isValid(..) method of my custom validator
@Override
public boolean isValid ( Ticket ticket, ConstraintValidatorContext context )
{
try
{
this.ticketService.verifyTicketExists( ticket.getId() );
return true;
} catch ( ResourceNotFoundException e )
{
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate( "Ticket with id " + ticket.getId() + " not found" )
.addConstraintViolation();
return false;
}
}
On runtime, everything works fine.
I would like to unit test my controller's submitTask method by mocking my custom constraint validator entirely or just mock the ticketService that the validator uses.
I have tried mocking the service and the validator "traditionally" (not at the same time) with Mockito.when(..) but i am getting a NullPointerException on the service.
Test attempt :
@RunWith ( SpringJUnit4ClassRunner.class )
@SpringApplicationConfiguration ( classes = MyApplication.class )
@ContextConfiguration ( classes = MockServletContext.class )
@WebAppConfiguration
public class TaskControllerTests
{
@InjectMocks
TaskController taskController;
@Mock
TaskService taskService;
@Mock
TicketService ticketService;
.
.
@Before
public void setup ()
{
MockitoAnnotations.initMocks( this );
mockMvc = standaloneSetup( this.taskController )
.setControllerAdvice( new RestExceptionHandler() )
.build();
}
.
.
@Test
public void submitTask () throws Exception
{
when( taskService.create( any( Task.class ) ) ).thenReturn( this.task );
doNothing().when( ticketService ).verifyTicketExists( 1L );
mockMvc.perform( post( "/api/task/newtask" ).content( "..validpayload..") ).andExpect( status().isCreated() );
}
}
I got it working by following this post by tomasz_kusmierczyk
The constraint validation factory i created can be found here and the creation of the "test validator" can be found here.
My custom validators (TicketExistsValidator
and UsersExistValidator
) make use of services internally (TicketService
and UserService
respectively). I create mocks of these services on my test and then pass in the mocked services to the factory (which then uses the setters of the validators to set the mock services).
After that, services can be mocked by using mockito.when().
In order for the annotation constraints (@NotNull, @Size) to work in tests, i had to annotate my controller with both @Valid and @Validated(CustomGroup.java).