tutorial test mvc java spring spring-mvc junit mockmvc

java - tutorial - Registre el controlador anotado @ControllerAdvice en JUnitTest con MockMVC



test spring controller (4)

Mi @ControllerAdvice anotado @ControllerAdvice ve así:

@ControllerAdvice public class GlobalControllerExceptionHandler { @ResponseStatus(value = HttpStatus.UNAUTHORIZED) @ExceptionHandler(AuthenticationException.class) public void authenticationExceptionHandler() { } }

Por supuesto, mi desarrollo está basado en pruebas y me gustaría usar mi Administrador de excepciones en las Pruebas JUnit. Mi caso de prueba se ve así:

public class ClientQueriesControllerTest { private MockMvc mockMvc; @InjectMocks private ClientQueriesController controller; @Mock private AuthenticationService authenticationService; @Before public void setup() { MockitoAnnotations.initMocks(this); mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); } @Test public void findAllAccountRelatedClientsUnauthorized() throws Exception { when(authenticationService.validateAuthorization(anyString())).thenThrow(AuthenticationException.class); mockMvc.perform(get("/rest/clients").header("Authorization", UUID.randomUUID().toString())) .andExpect(status().isUnauthorized()); } }

Probablemente necesito registrar la clase ControllerAdvice . ¿Como hacer eso?


Desde la primavera 4.2, puede registrar su ControllerAdvice directamente en su StandaloneMockMvcBuilder:

MockMvcBuilders .standaloneSetup(myController) .setControllerAdvice(new MyontrollerAdvice()) .build();


Para que la configuración completa de Spring MVC se active, debe usar MockMvcBuilders.webAppContextSetup lugar de MockMvcBuilders.standaloneSetup .

Echa un vistazo a docs.spring.io/spring-framework/docs/current/… parte de la documentación de Spring para más detalles.

Su código se vería como:

@RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration("test-config.xml") public class ClientQueriesControllerTest { private MockMvc mockMvc; @Autowired private WebApplicationContext webApplicationContext; @Autowired private AuthenticationService authenticationService; @Before public void setup() { MockitoAnnotations.initMocks(this); mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); } @Test public void findAllAccountRelatedClientsUnauthorized() throws Exception { when(authenticationService.validateAuthorization(anyString())).thenThrow(AuthenticationException.class); mockMvc.perform(get("/rest/clients").header("Authorization", UUID.randomUUID().toString())) .andExpect(status().isUnauthorized()); } }

Luego, dentro de test-config.xml usted agregaría un bean Spring para AuthenticationService que es un simulacro.

<bean id="authenticationService" class="org.mockito.Mockito" factory-method="mock"> <constructor-arg value="your.package.structure.AuthenticationService"/> </bean>

Por supuesto, puede usar perfiles para inyectar el AuthenticationService simulado en las pruebas si desea reutilizar su archivo de configuración Spring normal en lugar de crear test-config.xml .

ACTUALIZAR

Después de investigar un poco, descubrí que StandaloneMockMvcBuilder devuelto por ( MockMvcBuilders.standaloneSetup ) es totalmente personalizable. Eso significa que puede conectar cualquier resolución que prefiera.

Sin embargo, dado que está utilizando @ControllerAdvice , el código siguiente no funcionará. Sin embargo, si su método @ExceptionHandler estaba dentro del mismo controlador, el código que tendría que cambiar es el siguiente:

mockMvc = MockMvcBuilders.standaloneSetup(controller).setHandlerExceptionResolvers(new ExceptionHandlerExceptionResolver()).build();

ACTUALIZACIÓN 2

Algunas excavaciones adicionales dieron la respuesta a cómo puede registrar un controlador de excepciones correcto cuando también está utilizando @ControllerAdvice .

Debe actualizar el código de configuración en la prueba a lo siguiente:

@Before public void setUp() throws Exception { final ExceptionHandlerExceptionResolver exceptionHandlerExceptionResolver = new ExceptionHandlerExceptionResolver(); //here we need to setup a dummy application context that only registers the GlobalControllerExceptionHandler final StaticApplicationContext applicationContext = new StaticApplicationContext(); applicationContext.registerBeanDefinition("advice", new RootBeanDefinition(GlobalControllerExceptionHandler.class, null, null)); //set the application context of the resolver to the dummy application context we just created exceptionHandlerExceptionResolver.setApplicationContext(applicationContext); //needed in order to force the exception resolver to update it''s internal caches exceptionHandlerExceptionResolver.afterPropertiesSet(); mockMvc = MockMvcBuilders.standaloneSetup(controller).setHandlerExceptionResolvers(exceptionHandlerExceptionResolver).build(); }


Pasé la excepción NestedServletException con la siguiente solución ...

final StaticApplicationContext applicationContext = new StaticApplicationContext(); applicationContext.registerSingleton("exceptionHandler", GlobalControllerExceptionHandler.class); final WebMvcConfigurationSupport webMvcConfigurationSupport = new WebMvcConfigurationSupport(); webMvcConfigurationSupport.setApplicationContext(applicationContext); mockMvc = MockMvcBuilders.standaloneSetup(controller). setHandlerExceptionResolvers(webMvcConfigurationSupport.handlerExceptionResolver()). build();


Puedes agregar esto a tu clase de prueba

@Autowired @Qualifier("handlerExceptionResolver") void setExceptionResolver(HandlerExceptionResolver resolver) { this.exceptionResolver = resolver; }

y luego agrega el exceptionResolver a tu MockMvc

@Before public void setup() { MockitoAnnotations.initMocks(this); mockMvc = MockMvcBuilders.standaloneSetup(controller) .setHandlerExceptionResolvers(this.exceptionResolver).build(); }