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() );
}
}
You can mock the validator entirely by using JMockit's @Mocked annotation:
public class Test {
@Mocked // mocks the class everywhere
TaskDependenciesDbConstraintValidator validator;
@Test
public void testMethod(){
new Expectations {{ // expect the validator to be called
validator.isValid((Ticket) any, (ConstraintValidatorContext) any);
result = true; // and declare the object to be valid
}}
// do your testing here
}
}
As for your example, if you're unit testing the controller, why bring up the whole Spring context? Because that's what you're doing with
@RunWith ( SpringJUnit4ClassRunner.class )
@SpringApplicationConfiguration ( classes = MyApplication.class )
@ContextConfiguration ( classes = MockServletContext.class )
@WebAppConfiguration
First and foremost, you should remove those and try again.