Te recomendamos que revises esta resolución en un entorno controlado antes de pasarlo a producción, un saludo.
Solución:
Quien esté interesado en cargar la aplicación completa debería intentar usar @SpringBootTest
combinado con @AutoConfigureMockMvc
en lugar del @WebMvcTest
.
He estado luchando con el problema durante bastante tiempo, pero finalmente obtuve la imagen completa.
Los numerosos tutoriales en Internet, así como la documentación oficial de Spring que encontré hasta ahora , indica que puedes probar tus controladores usando @WebMvcTest
; eso es completamente correcto, aunque todavía omite la mitad de la historia.
Como lo señala el javadoc de dicha anotación, @WebMvcTest
solo está destinado a probar sus controladores y no cargará todos los beans de su aplicación en absoluto, y esto es por diseño.
Incluso es incompatible con anotaciones explícitas de escaneo de beans como @Componentscan
.
Sugiero a cualquier persona interesada en el asunto que lea el javadoc completo de la anotación (que tiene solo 30 líneas y está repleto de información útil condensada), pero extraeré un par de gemas relevantes para mi situación.
del tipo de anotación WebMvcTest
El uso de esta anotación deshabilitará la configuración automática completa y, en su lugar, aplicará solo la configuración relevante para las pruebas MVC (es decir,
@Controller
,@ControllerAdvice
,@JsonComponent
Filtrar,WebMvcConfigurer
yHandlerMethodArgumentResolver
frijoles pero no@Component
,@Service
o@Repository
frijoles). […]
Si está buscando cargar la configuración completa de su aplicación y usar MockMVC, debe considerar@SpringBootTest
combinado con@AutoConfigureMockMvc
en lugar de esta anotación.
Y en realidad, solo @SpringBootTest
+ @AutoConfigureMockMvc
solucionó mi problema, todos los demás enfoques que hacían uso de @WebMvcTest
no pudo cargar algunos de los beans necesarios.
EDITAR
Retiro mi comentario que hice sobre la documentación de Spring, porque no sabía que un rodaja estaba implícito cuando uno usa un @WebMvcTest
; en realidad, la documentación del segmento MVC deja en claro que no toda la aplicación está cargada, lo cual es por la naturaleza misma de un segmento.
Rebanada de prueba personalizada con Spring Boot 1.4
La segmentación de la prueba consiste en segmentar el ApplicationContext que se crea para su prueba. Típicamente, si desea probar un controlador usando MockMvc, seguramente no querrá molestarse con la capa de datos. En su lugar, probablemente desee burlarse del servicio que usa su controlador y validar que toda la interacción relacionada con la web funciona como se espera.
Tu estas usando @WebMvcTest
al mismo tiempo que configura manualmente un MockMvc
ejemplo. Eso no tiene sentido como uno de los propósitos principales de @WebMvcTest
es configurar automáticamente un MockMvc
instancia para ti. Además, en su configuración manual está utilizando standaloneSetup
lo que significa que debe configurar completamente el controlador que se está probando, incluida la inyección de cualquier dependencia en él. No estás haciendo eso que causa la NullPointerException
.
Si quieres usar @WebMvcTest
, y te recomiendo que lo hagas, puedes eliminar tu setUp
método completamente y tener un autoconfigurado MockMvc
instancia inyectada en lugar de usar una @Autowired
campo.
Entonces, para controlar el ProductService
eso es usado por ProductController
, puedes usar el nuevo @MockBean
anotación para crear un simulacro ProductService
que luego se inyectará en ProductController
.
Estos cambios dejan su clase de prueba con este aspecto:
package guru.springframework.controllers;
import guru.springframework.services.ProductService;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(SpringRunner.class)
@WebMvcTest(ProductController.class)
public class ProductControllerTest
@Autowired
private MockMvc mockMvc;
@MockBean
private ProductService productService;
@Test
public void testList() throws Exception
mockMvc.perform(MockMvcRequestBuilders.get("/products"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.view().name("products"))
.andExpect(MockMvcResultMatchers.model().attributeExists("products"))
.andExpect(MockMvcResultMatchers.model().attribute("products",
Matchers.is(Matchers.empty())));